繁体   English   中英

参数类型的scala中的咖喱

[英]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>

参见https://stackoverflow.com/a/4593509/21640

您在这里遇到两个单独的问题。 首先是传递给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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM