Scala 如何使用Shapeless创建一个抽象于arity的函数 让我们考虑一个具体的例子。我有很多函数,它们接受可变数量的参数,并返回一个Seq[T]。说: def nonNeg(start: Int, count: Int): Seq[Int] = Iterator.from(start).take(count).toSeq

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版本”,返回
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的成员时,为什么会产生错误值?