作者说:
def foo[A](fst: List[A], snd: List[A]): List[A]
我们实现该功能的方式较少。特别是我们 不能只是对列表中的某些元素进行硬编码,因为我们没有 能够制造任意类型的价值。
我不理解这一点,因为在[Char]
版本中我们也无法制作任意类型的值,我们必须使用类型为[Char]
的类型,所以为什么实现的方法较少此?
答案 0 :(得分:5)
在通用版本中,您知道输出列表只能包含fst
和snd
中包含的元素的某些排列,因为无法构造某些任意类型的新值{{1 }}。相反,如果你知道输出类型是A
,你可以例如。
Char
此外,您不能使用输入列表中包含的值来做出影响输出的决策,因为您不知道它们是什么。如果您知道输入类型,则可以执行此操作,例如
def foo(fst: List[Char], snd: List[Char]) = List('a', 'b', 'c')
答案 1 :(得分:3)
我假设作者的意思是,没有办法构建非空List a
但是有一种方法可以构建List Char
,例如通过使用字符串文字。你可以忽略参数,只返回一个硬编码的字符串。
这方面的一个例子是:
foo :: List Char -> List Char -> List Char
foo a b = "Whatever"
您无法构造任意类型a
的值,但您可以构造Char
类型的值。
答案 2 :(得分:2)
这是一个名为"parametricity"或“自由定理”的属性的简单情况,它适用于每个多态函数。
更简单的例子如下:
fun1 :: Int -> Int
fun2 :: forall a. a -> a
fun1
可以是任何东西:后继者,前任者,正方形,阶乘法等。这是因为它可以“读取”其输入,并采取相应的行动。
fun2
必须是身份功能(或永远循环)。这是因为fun2
接收了它的输入,但它无法以任何有用的方式检查它:因为它是一个抽象的未知类型a
,所以不能对它执行任何操作。输入实际上是一个不透明的令牌。 foo2
的输出必须是a
类型,我们不知道任何构造方法 - 我们无法从零开始创建类型a
的值。唯一的选择是获取输入a
并使用它来制作输出a
。因此,fun2
是身份。
当您无法对输入或类型a
执行测试时,上述参数化结果成立。如果我们(例如,允许if x.instanceOf[Int] ...
或if x==null ...
或类型转换(在OOP中),那么我们可以用其他方式编写fun2
。