带有参数类型

时间:2016-03-19 20:41:15

标签: scala functional-programming currying

Scala中的函数式编程的作者give this作为scala中curry的定义:

def curry[A,B,C](f: (A, B) => C): A => (B => C) =
    a => b => f(a, b)

但是,如果我们将它应用于采用参数类型的函数,例如:

def isSorted[A](as: Array[A], ordered:(A,A)=>Boolean) =
    if(as.size < 2)
        true else
           as.zip(as.drop(1)).map(ordered.tupled).reduce(_ && _)

然后结果希望A(在isSorted中)无效:

scala> curry(isSorted)
res29: Array[Nothing] => (((Nothing, Nothing) => Boolean) => Boolean) = <function1>

这显然不是所期望的。咖喱应该用不同的方式定义,还是用不同的方式调用,或者在Scala中实现curry是不切实际的?

2 个答案:

答案 0 :(得分:3)

事实证明我可以这样叫咖喱:

curry(isSorted[Int])

哪个收益率:

scala> curry(isSorted[Int])
res41: Array[Int] => (((Int, Int) => Boolean) => Boolean) = <function1>

请参阅https://stackoverflow.com/a/4593509/21640

答案 1 :(得分:3)

你在这里遇到了两个不同的问题。第一个是isSorted传递给curry时被强制变为单态。第二个是Scala的类型推断让你失败了。

这是Scala中function and a method之间的区别之一。 isSorted被eta扩展为一个函数,而函数又是一个Scala值,而不是一个方法。 Scala值始终是单态的,只有方法可以是多态的。对于任何类型(A, B) C的方法(这是method type的语法,并且不同于(A, B) => C,它是一个函数,因此是一个值),默认的eta-expansion将会产生结果在该arity的所有函数的超类中,即(Nothing, Nothing) => Any。这对您看到的所有Nothing负责(您没有Any因为isSorted的返回值是单态的。)

你可能会想象尽管Scala值的单形性质,你可以理想地做一些像

这样的事情。
def first[A, B](x: A, y: B): A = x
curry(first)(5)(6) // This doesn't compile

这是Scala的本地类型推断咬你。它适用于从左到右的单独参数列表first是获得类型推断的第一件事,如上所述,它被推断为(Nothing, Nothing) => Any。这与随后的Int冲突。

正如您已经意识到的,解决此问题的一种方法是注释您传递给curry的多态方法,以便它可以扩展为正确的类型。这几乎肯定是要走的路。

你可能做的另一件事(虽然我不认为除了教学目的之外它会提供任何服务)是为了讨论curry本身,并按如下方式定义:

def curryTwo[A, B, C](x: A)(y: B)(f: (A, B) => C): C = f(x, y)

一方面,由于从左到右的类型推断,现在下面的工作正常。

curryTwo(5)(6)(first) // 5

另一方面,要在您希望使用curryTwo的情况下使用curry,您需要向Scala&#39提供类型;无论如何都是类型推理引擎。