Scala中的多态函数是"限制性的"吗?

Som*_*kar 13 scala polymorphic-functions

在Scala MEAP v10中的功能编程一书中,作者提到了这一点

多态函数通常受其类型约束,因此它们只有一个实现!

并举例说明

def partial1[A,B,C](a: A, f: (A,B) => C): B => C = (b: B) => f(a, b)
Run Code Online (Sandbox Code Playgroud)

这句话是什么意思?多态函数是否具有限制性?

Jör*_*tag 20

这是一个更简单的例子:

def mysteryMethod[A, B](somePair: (A, B)): B = ???
Run Code Online (Sandbox Code Playgroud)

这种方法有什么作用?事实证明,这种方法只能做件事!您不需要方法的名称,您不需要执行该方法,您不需要任何文档.该类型告诉你它可能做的一切,事实证明在这种情况下"一切"只是件事.

那么,它做了什么?它需要一对(A, B)并返回一些类型的值B.它返回什么价值?它可以构造一个类型的值B吗?不,它不能,因为它不知道是什么B!它可以返回类型的随机值B吗?不,因为随机性是副作用,因此必须出现在类型签名中.它可以在宇宙中出现并获取一些B吗?不,因为会产生副作用,并且必须出现在类型签名中!

实际上,它唯一能做的就是返回B传递给它的类型的值,这是该对的第二个元素.所以,这mysteryMethod真的是second方法,它唯一明智的实现是:

def second[A, B](somePair: (A, B)): B = somePair._2
Run Code Online (Sandbox Code Playgroud)

请注意,实际上,由于Scala既不是纯粹的也不是完全的,实际上该方法还可以执行其他一些操作:抛出异常(即异常返回),进入无限循环(即根本不返回),使用反射以找出实际类型B并反射调用构造函数来构造新值等.

但是,假设纯度(返回值可能只取决于参数),totality(方法必须正常返回一个值)和参数(它实际上并不知道任何关于AB),那么实际上你可以有很多通过查看其类型来讲述方法.

这是另一个例子:

def mysteryMethod(someBoolean: Boolean): Boolean = ???
Run Code Online (Sandbox Code Playgroud)

这有什么作用?它总是可以返回false并忽略它的论点.但是它会受到过度约束:如果它总是忽略它的论点,那么它并不关心它是一个Boolean它的类型宁愿是

def alwaysFalse[A](something: A): Boolean = false // same for true, obviously
Run Code Online (Sandbox Code Playgroud)

它总是可以只返回它的论点,但是再一次,它实际上并不关心布尔值,它的类型宁愿

def identity[A](something: A): A = something
Run Code Online (Sandbox Code Playgroud)

所以,真的,它唯一能做的就是返回一个不同于传入的布尔值,因为只有两个布尔值,我们知道我们的mysteryMethod实际上是not:

def not(someBoolean: Boolean): Boolean = if (someBoolean) false else true
Run Code Online (Sandbox Code Playgroud)

所以,在这里,我们有一个例子,这里的类型不给我们实现,但至少,他们给的(小)组的4级可能的实现,其中只有一个是有道理的.

(顺便说一句:事实证明,只有一种方法的可能实现,它接受A并返回一个A,并且它是上面显示的身份方法.)

所以,回顾一下:

  • 纯度意味着你只能使用交给你的构建块(参数)
  • 一个强大,严格的静态类型系统意味着您只能以这样的方式使用这些构建块,使其类型排列
  • totality意味着你不能做愚蠢的事情(比如无限循环或抛出异常)
  • 参数化意味着您无法对类型变量做任何假设

将您的参数视为机器的一部分,将您的类型视为这些机器部件上的连接器.只有有限数量的方法可以将这些机器部件连接在一起,只需将兼容的连接器插在一起,并且没有任何剩余部件.通常情况下,只有一种方式,或者如果有多种方式,那么通常一种方式显然是正确方式.

这意味着,一旦你设计了对象和方法的类型,你甚至不必考虑如何实现这些方法,因为类型已经规定了实现它们的唯一可能方法!考虑StackOverflow上有多少的问题基本上都是"我怎么实现这一点?",你可以想像释放它必须没有怎么考虑这个问题的所有,因为该类型已经决定了一个(或几个之一)可能实现?

现在,看看在你的问题的方法的签名,并尝试用不同的方式来结合玩耍a,并f以这样的方式,该类型的排队,同时使用af,你的确会看到,只有一个做到这一点的方法.(正如克里斯和保罗所示.)

  • 很好的解释,但我不确定它的纯度,总体和参数的假设有多大!如果你没有全部三种类型,那么你会比你想象的要少得多.例如,`mysteryMethod((A,B))`很可能是在`A`和`mysteryMethod(布尔)`上匹配的选择或默认操作模式,很可能是一个日志记录或映射放置操作.这些东西真的很有用,但知道方法单独从类型中做什么也是如此,并且你不可能同时拥有两者. (4认同)

The*_*aul 5

def partial1[A,B,C](a: A, f: (A,B) => C): B => C = (b: B) => f(a, b)
Run Code Online (Sandbox Code Playgroud)

这里,partial1作为类型A的参数值,以及采用类型A的参数和类型B的参数的函数,返回类型C的值.

partial1必须返回一个取B型值并返回C的函数.鉴于A,B和C是任意的,我们不能对它们的值应用任何函数.所以唯一的可能性是将函数f应用于a传递给partial的值,以及类型B的值,它是我们返回的函数的参数.

所以你最终得到了定义中的单一可能性 f(a,b)