scala - 如何使用 Shapeless 创建一个对 arity 进行抽象的函数

标签 scala shapeless

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

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

对于这些函数中的每一个,我需要创建该函数的“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使用 Shapeless 编写能力 abstracting over arity ?如果可以,如何做,不能,为什么以及如何做?

最佳答案

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

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]
javaNonNegFunction2 , 所以从 Java 你可以使用 javaNonNeg.apply(1, 4) .

关于scala - 如何使用 Shapeless 创建一个对 arity 进行抽象的函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25149179/

相关文章:

Scala actor 显然没有收到消息

scala - 如何优化 Spark 以将大量数据写入 S3

scala - 找不到 Ordered[T] 类型的证据参数的隐式值

string - 在 Scala 中修剪字符串

scala - Scala 中的不可变数据结构

scala - 如何通过组合输入元组来组成元组一元函数

scala - 类型参数声明中的无形解构元组

java - scala -> java getField().get()

scala - Shapeless 在测试中找不到隐式,但可以在 REPL 中找到

scala - 无形:在 HList 上反转 filterNot