如何使用 Shapeless 创建一个对 arity 进行抽象的函数 [英] How can I use Shapeless to create a function abstracting over arity

查看:38
本文介绍了如何使用 Shapeless 创建一个对 arity 进行抽象的函数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

让我们考虑一个具体的例子.我有很多函数接受可变数量的参数,并返回一个 Seq[T].说:

Let's consider a specific example. I have lots of functions that take a variable number of arguments, and return a Seq[T]. Say:

def nonNeg(start: Int, count: Int): Seq[Int] = 
    Iterator.from(start).take(count).toSeq

对于这些函数中的每一个,我需要创建该函数的Java 版本",返回一个 java.util.List[T].我可以使用以下命令创建上述函数的Java 版本":

For each one of those function, I need to create a "Java version" of that function, returns a java.util.List[T]. I can create the "Java version" of the above function with:

def javaNonNeg(start: Int, count: Int): java.util.List[Int] =
    nonNeg(start, count).asJava

这有点冗长,因为参数列表重复了两次.相反,我想创建一个更高级别的函数,它将 nonNeg 形式的函数作为参数(任何数量和类型的参数,返回一个 Seq[T]) 并返回一个具有相同参数的函数,但返回一个 java.util.List[T].假设该函数被称为 makeJava,那么我就可以这样写:

This is somewhat verbose, as the list of parameters is duplicated twice. Instead, I'd like to create a higher level function that takes as a parameter a function of the form of nonNeg (any number and type of arguments, returns a Seq[T]) and returns a function which takes the same arguments, but returns a java.util.List[T]. Assuming that function was called makeJava, I'd then be able to write:

def javaNonNeg = makeJava(nonNeg)

可以使用 Shapeless 能力编写 makeJava对arity进行抽象?如果可以,如何做,不能,为什么以及如何做?

Can makeJava be written using Shapeless ability to abstracting over arity? If it can, how, and it not, why and how else can this be done?

推荐答案

可以使用 Shapeless 来避免样板文件——您只需要使用普通的旧 eta 将原始方法转换为 FunctionN展开,然后转换为带有单个 HList 参数的函数,然后返回具有新结果类型的 FunctionN:

It is possible to use Shapeless to avoid the boilerplate—you just need to turn the original method into a FunctionN using plain old eta expansion, then convert to a function taking a single HList argument, and then back to a FunctionN with the new result type:

import java.util.{ List => JList }
import shapeless._, ops.function._
import scala.collection.JavaConverters._

def makeJava[F, A, L, S, R](f: F)(implicit
  ftp: FnToProduct.Aux[F, L => S],
  ev: S <:< Seq[R],
  ffp: FnFromProduct[L => JList[R]]
) = ffp(l => ev(ftp(f)(l)).asJava)

然后:

scala> def nonNeg(start: Int, count: Int): Seq[Int] = 
     |     Iterator.from(start).take(count).toSeq
nonNeg: (start: Int, count: Int)Seq[Int]

scala> val javaNonNeg = makeJava(nonNeg _)
javaNonNeg: (Int, Int) => java.util.List[Int] = <function2>

scala> javaNonNeg(1, 4)
res0: java.util.List[Int] = [1, 2, 3, 4]

javaNonNeg 是一个 Function2,所以在 Java 中你可以使用 javaNonNeg.apply(1, 4).

javaNonNeg is a Function2, so from Java you can use javaNonNeg.apply(1, 4).

这篇关于如何使用 Shapeless 创建一个对 arity 进行抽象的函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆