我想知道你是否可以编写一个泛型函数,它接受一个curried函数,然后反转参数,如下所示:
def foo(a: String)(b: Boolean)(c: Int): String val bar = invert(foo _) foo("baz")(false)(12) must be equalTo(bar(12)(false)("baz"))
只要您为要解决的特定情况添加隐式逆变器,以下操作就可以正常工作.但我对更一般的情况更感兴趣 – 也就是说,处理任何数量的讨论论点的情况.
trait Inverter[V,W] { def invert(v: V): W } implicit def function2Inverter[X,Y,Z] = new Inverter[(X,Y) => Z,(Y,X) => Z] { def invert(v: (X,Y) => Z) = { def inverted(y: Y,x: X) = v(x,y) inverted _ } } implicit def curried2Inverter[X,Z] = new Inverter[X => Y => Z,Y => X => Z] { def invert(v: (X) => (Y) => Z) = { def inverted(y: Y)(x: X) = v(x)(y) inverted _ } } def invert[V,W](v: V)(implicit inverter: Inverter[V,W]): W = inverter.invert(v)
哦,我希望有一个适用于Scala 2.9的解决方案.
解决方法
TL; DR:使用
this gist.以下说明如下:
首先,定义一个类型类(和个案)以部分应用具有最后一个参数的函数:
trait PopLast[A,Last,Rem] { def pop(f: A,v: Last): Rem } trait LowPrioPopLast { implicit def popEnd[A,B] = new PopLast[A => B,A,B] { def pop(f: A => B,v: A) = f(v) } } object PopLast extends LowPrioPopLast { implicit def popOne[A,B,C,IRem]( implicit iPop: PopLast[B => C,IRem]) = new PopLast[A => B => C,A => IRem] { def pop(f: A => B => C,v: Last) = { a: A => iPop.pop(f(a),v) } } }
然后,创建逆变器类型类:递归地执行最后一个参数的部分应用并反转结果.
trait Inverter[A] { type Out def invert(f: A): Out } trait LowPrioInverter { implicit def invertEnd[A,B] = new Inverter[A => B] { type Out = A => B def invert(f: A => B) = f } } object Inverter extends LowPrioInverter { implicit def invertStep[A,Rem](implicit pop: PopLast[A,Rem],inv: Inverter[Rem]) = new Inverter[A] { type Out = Last => inv.Out def invert(f: A) = { a: Last => inv.invert(pop.pop(f,a)) } } }
最后,封装成一个函数:
def invert[A](f: A)(implicit inv: Inverter[A]) = inv.invert(f)
然后我们去:
def foo(a: String)(b: Boolean)(c: Int): String = "bar" val bar = invert(foo _) // bar: Int => Boolean => String => String bar(1)(true)("foo")