在使用无形的arity的摘要

时间:2017-10-25 17:18:01

标签: scala shapeless

使用无形状我们可以使用他们的文档中描述的配方来抽象arity。

def applyProduct[P <: Product, F, L <: HList, R](p: P)(f: F)(implicit gen: Generic.Aux[P, L], fp: FnToProduct.Aux[F, L => R]) =
  f.toProduct(gen.to(p))

val add = (x: Int, y: Int) => x + y

def wrapper[F](f: F) {
  applyProduct(1, 2)(f)
}

wrapper(add)

但是,我无法包装此设施,例如:

find implicit value for parameter fp: shapeless.ops.function.FnToProduct.Aux[(A, A) => A,L => R]

编译器辩称它不能case class Node[P <: Product, F, L <: HList, R](f: F)(implicit gen:Generic.Aux[P, L], fp: FnToProduct.Aux[F, L => R]) { def evaluate(p: P) = { f.toProduct(gen.to(p)) } }

意味着它无法将K-ary函数转换为相同参数类型的K大小的HList函数。

我怎样才能让它发挥作用?

修改

好的,现在想象一下我在某个时间知道这个功能,但我稍后会知道这些论点,所以我想推迟评估

val add = (x: Int, y: Int) => x + y

val n = Node(add)

//later

n.evaluate(1,2,3)

编译器不允许我调用:

${javascript:

我不能用部分应用来解决这个问题吗?

1 个答案:

答案 0 :(得分:3)

就这么简单:

def wrapper[R](f: (Int, Int) => R) = {
  applyProduct(1, 2)(f)
}

您已经通过在包装器中传递P来定义(Int, Int)类型(作为(1,2)),因此对F进行抽象没有任何意义 - 仅限R你可以抽象的东西是applyProduct(结果类型)

说明:

wrapper内的{p> FFnToProduct.Aux[F, ...]一无所知。因此,为了隐式查找F scala编译器需要知道有关FnToProduct.Aux是什么的更多信息,导致在其上隐式定义(A, A) => A的“形状”为{{1} (在你的情况下是(Int, Int) => Int),而不仅仅是F,哪个编译器从错误信息中诚实地告诉你。

对编辑的回应:

@ applyProduct(_: Int, _: Int)(add) 
res17: (Int, Int) => Int = 

@ res17(1,2) 
res18: Int = 3

为了避免类型归属,您可以使用类似Node案例类的东西(使用案例类来避免new不被认为是一种好的风格),但不引入类(只是从函数返回lambda)。但是,与Node一样,如果不传递所有类型参数,Scala将无法进行正确的类型推断。

不幸的是,你不能在这里方便地使用currying(通过使f: F成为第一个参数)因为“implicits”在没有传递所有类型参数的情况下无法解决。也许有办法破解它,但部分应用似乎最简单易懂。

P.S。然而,您可能会注意到,对于这种情况,此类部分应用程序等同于:

@ val ff = add _; val f = ff() 
ff: () => (Int, Int) => Int = 
f: (Int, Int) => Int = ammonite.$sess.cmd9$$$Lambda$1978/545666041@6e7e60bb

@ f(1,2) 
res34: Int = 3

拥有一个带有两个(或List of)参数(reducer)的函数更有意义,但是转换为任意arity的函数,比如def abstract[...](f: (A, A) => A)(p: P): A。这将是对arity的更真实的抽象。