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)
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只返回未触及的函数.)