编写一个函数来curry任何函数

dop*_*man 3 haskell functional-programming scala

为了记录,我发现在Scala中不会自动计算函数非常烦人.我正在尝试编写一个接收任何函数并返回curried版本的工厂:

def curry(fn:(_ => _)) = (fn _).curried
Run Code Online (Sandbox Code Playgroud)

基本上我在这里定义的是一个函数curry,它将一个fn类型的函数作为参数,_ => _并返回一个curried版本的函数fn.显然这不起作用,因为Java.

这是我得到的错误:

error: _ must follow method; cannot follow fn.type
       def curry(fn:(_ => _)) = (fn _).curried
Run Code Online (Sandbox Code Playgroud)

任何大师都可以帮我弄清楚为什么这不起作用?我并不是说听起来很讽刺,我习惯于将所有类型作为函数处理的函数式语言.请帮助这个Scala新手.

(我用haskell标记了这个问题,因为我试图让Scala函数表现得像Haskell函数:'(

UPDATE

只是为了澄清,我需要一个curryN函数,所以一个函数可以调整任何其他函数而不管它是什么.

旁注,有人指出增加fn参数的数量可以解决问题.不:

def curry2(fn:((_, _) => _)) = (fn _).curried
error: _ must follow method; cannot follow fn.type
       def curry2(fn:((_, _) => _)) = (fn _).curried
Run Code Online (Sandbox Code Playgroud)

Rex*_*err 7

Scala不允许您对函数的arity进行抽象.因此,您需要使用类型类方法(在完成所有手动工作之后,它允许您抽象几乎任何东西).

所以,特别是你做的事情

sealed trait FunctionCurrier[Unc, Cur] { def apply(fn: Unc): Cur }
final class Function2Currier[A, B, Z]
extends FunctionCurrier[(A, B) => Z, A => B => Z] {
  def apply(fn: (A, B) => Z): (A => B => Z) = fn.curried
}
// Repeat for Function3 through Function21

implicit def makeCurrierForFunction2[A, B, Z]: Function2Currier[A, B, Z] =
  new Function2Currier[A, B, Z]
// Again, repeat for Function3 through Function21

def curryAll[Unc, Cur](fn: Unc)(implicit cf: FunctionCurrier[Unc, Cur]): Cur =
  cf(fn)
Run Code Online (Sandbox Code Playgroud)

现在您可以像这样使用它:

scala> def foo(a: Int, b: String) = a < b.length
foo: (a: Int, b: String)Boolean

scala> curryAll(foo _)
res0: Int => (String => Boolean) = <function1>
Run Code Online (Sandbox Code Playgroud)

在Shapeless中可能已经有类似的东西了,但在这种情况下你可以自己滚动,虽然有些乏味(和/或代码生成器).

(注意:如果你想"咖喱" A => Z,你可以编写一个Function1Currier只返回未触及的函数.)

  • 在你走路之前你想跑步.如果你真的不明白什么类型参数("方括号中的参数"),那么尝试编写一般函数 - currier可能还为时过早.无形:https://github.com/milessabin/shapeless (2认同)