有没有通用的方法来反转柯里化函数的参数顺序? [英] Is there a generic way to invert the order of the arguments of a curried function?

查看:42
本文介绍了有没有通用的方法来反转柯里化函数的参数顺序?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想知道您是否可以编写一个泛型函数,它接受一个柯里化函数然后反转参数,如下所示:

I was wondering if you can write a generic function that takes a curried function and then inverts the arguments, like this:

def foo(a: String)(b: Boolean)(c: Int): String
val bar = invert(foo _)
foo("baz")(false)(12) must be equalTo(bar(12)(false)("baz"))

只要您为要解决的特定情况添加隐式反相器,以下内容就可以工作.但我对更一般的情况更感兴趣——即处理任意数量的柯里化参数的情况.

The below is working as long as you add implicit inverters for the specific cases you want to address. But I am more interested in the more general case – that is, the case that deals with any number of curried arguments.

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, 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 _
    }
  }

def invert[V, W](v: V)(implicit inverter: Inverter[V, W]): W = 
  inverter.invert(v)

哦,我很想有一个也适用于 Scala 2.9 的解决方案.

Oh, and I would love to have a solution that works with Scala 2.9 as well.

推荐答案

TL;DR:使用这个要点.相同的解释如下:

TL;DR: Use this gist. Explanation of the same follows:

首先,定义一个类型类(和案例)来部分应用带有最后一个参数的函数:

First, define a type class (and cases) to partially apply a function with the last parameter:

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, Last, IRem](
    implicit iPop: PopLast[B => C, Last, IRem]) = 
      new PopLast[A => B => C, Last, A => IRem] {
        def pop(f: A => B => C, v: Last) = { a: A => iPop.pop(f(a), v) }
      }
}

然后,创建逆变器类型类:递归地对最后一个参数进行部分应用,并将结果取反.

Then, create the inverter type class: recursively do partial application of last parameter and invert the result.

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, Last, Rem](implicit pop: PopLast[A, Last, 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")

这篇关于有没有通用的方法来反转柯里化函数的参数顺序?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆