[英]Curry in scala with parametric types
函数式编程的斯卡拉作者把这个作为的定义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
)为isSorted
:
scala> curry(isSorted)
res29: Array[Nothing] => (((Nothing, Nothing) => Boolean) => Boolean) = <function1>
这显然不是所希望的。 咖喱的定义应该不同,还是叫不同,还是在Scala中实施咖喱不切实际?
原来我可以这样称呼咖喱:
curry(isSorted[Int])
产生:
scala> curry(isSorted[Int])
res41: Array[Int] => (((Int, Int) => Boolean) => Boolean) = <function1>
您在这里遇到两个单独的问题。 首先是传递给curry
isSorted
被强制变为单态。 第二个是Scala的类型推断使您在这里失败。
这是在Scala中函数与方法之间的差异很重要的时代之一。 isSorted
被eta扩展为一个函数,该函数又是一个Scala值,而不是方法。 Scala值始终是单态的,只有方法可以是多态的。 对于任何类型为(A, B) C
(这是方法类型的语法,不同于(A, B) => C
是一个函数,因此是一个值),默认的eta-expansion将用于导致该类所有功能的超类,即(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
从左到右在单独的参数列表上工作, first
是要推断类型的事情,如上所述,它被推断为(Nothing, Nothing) => Any
。 这与随后的Int
冲突。
正如您已经意识到的那样,解决此问题的一种方法是注释传递给curry
多态方法,以便将其eta-展开为正确的类型。 这几乎肯定是要走的路。
您可能可以做的另一件事(尽管我认为除了教学目的之外,它不会有其他用途)是咖喱curry
本身,并将其定义如下:
def curryTwo[A, B, C](x: A)(y: B)(f: (A, B) => C): C = f(x, y)
一方面,由于从左到右的类型推断,以下内容现在可以使用。
curryTwo(5)(6)(first) // 5
另一方面,要在想要使用curry
的场景中使用curryTwo
,则无论如何都需要为Scala的类型推断引擎提供类型。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.