Scala 如何使用Shapeless创建一个抽象于arity的函数 让我们考虑一个具体的例子。我有很多函数,它们接受可变数量的参数,并返回一个Seq[T]。说: def nonNeg(start: Int, count: Int): Seq[Int] = Iterator.from(start).take(count).toSeq
对于这些函数中的每一个,我需要创建该函数的“Java版本”,返回Scala 如何使用Shapeless创建一个抽象于arity的函数 让我们考虑一个具体的例子。我有很多函数,它们接受可变数量的参数,并返回一个Seq[T]。说: def nonNeg(start: Int, count: Int): Seq[Int] = Iterator.from(start).take(count).toSeq,scala,shapeless,Scala,Shapeless,对于这些函数中的每一个,我需要创建该函数的“Java版本”,返回Java.util.List[T]。我可以使用以下方法创建上述函数的“Java版本”: def javaNonNeg(start: Int, count: Int): java.util.List[Int] = nonNeg(start, count).asJava 这有点冗长,因为参数列表重复了两次。相反,我想创建一个更高级别的函数,该函数将nonNeg(任意数量和类型的参数,返回一个Seq[T])形式的函数作为参数,并
Java.util.List[T]
。我可以使用以下方法创建上述函数的“Java版本”:
def javaNonNeg(start: Int, count: Int): java.util.List[Int] =
nonNeg(start, count).asJava
这有点冗长,因为参数列表重复了两次。相反,我想创建一个更高级别的函数,该函数将nonNeg
(任意数量和类型的参数,返回一个Seq[T]
)形式的函数作为参数,并返回一个具有相同参数的函数,但返回一个java.util.List[T]
。假设该函数被调用为makeJava
,那么我就能够编写:
def javaNonNeg = makeJava(nonNeg)
makeJava
是否可以使用以下功能编写?如果可以,怎么做,不可以,为什么以及怎么做?对于2个及以上(代码从下面到4)参数,您可以使用隐式参数功能,按输入参数类型解析结果类型
sealed trait FuncRes[F] {
type Param
type Result
def func : F => Param => Result
}
class Func[T, R](fn : T => R) {
trait FR[F, P] extends FuncRes[F] { type Param = P; type Result = R }
implicit def func2[T1,T2] = new FR[(T1,T2) => T, (T1,T2)] {
def func = f => p => fn(f.tupled(p))
}
implicit def func3[T1,T2,T3] = new FR[(T1,T2,T3) => T, (T1,T2,T3)] {
def func = f => p => fn(f.tupled(p))
}
implicit def func4[T1,T2,T3,T4] = new FR[(T1,T2,T3,T4) => T, (T1,T2,T3,T4)] {
def func = f => p => fn(f.tupled(p))
}
def makeFunc[F](f : F)(implicit ev : FuncRes[F]): ev.Param => ev.Result =
ev.func(f)
}
在您的defjavanonneg=makeJava(nonNeg)
函数如下所示:
object asJavaFunc extends Func((_ : Seq[Int]).asJava)
import asJavaFunc._
def javaNonNeq = makeFunc(nonNeg _)
当然它也有一些缺点,但通常它满足您的需要。可以使用Shapeless来避免样板文件,您只需使用普通的旧eta扩展将原始方法转换为
函数,然后转换为使用单个HList
参数的函数,然后返回带有新结果类型的函数n
:
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)
import java.util.{List=>JList}
导入无形状。u,ops.function_
导入scala.collection.JavaConverters_
def makeJava[F,A,L,S,R](F:F)(隐式
ftp:FnToProduct.Aux[F,L=>S],
ev:S 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]
scala>def nonNeg(开始:Int,计数:Int):Seq[Int]=
|迭代器.from(开始).take(计数).toSeq
非负:(起始:Int,计数:Int)Seq[Int]
scala>val javaNonNeg=makeJava(nonNeg)
javaNonNeg:(Int,Int)=>java.util.List[Int]=
scala>javaNonNeg(1,4)
res0:java.util.List[Int]=[1,2,3,4]
javaNonNeg
是一个函数2
,因此从Java可以使用javaNonNeg.apply(1,4)
非常好,这很有效,但需要相当多的“样板文件”(第一块代码中的所有代码)。在标准库或其他“主流”库(如Shapeless)中难道不会有类似的东西吗?这正是我想要的。非常感谢。顺便说一句,你知道为什么需要显式调用ev()
?既然可以使用从S
到Seq[R]
的“隐式转换”,为什么我不能直接编写ffp(l=>(ftp(f)(l)).asJava)
?当Java不是类型参数S的成员时,为什么会产生错误值?