Eas*_*ude 0 recursion haskell functional-programming list where
我几天前开始研究Haskell,经历了基础知识,还有一些我无法理解的事情.
首先,当我尝试在GHCi控制台中使用':'运算符向列表的开头添加内容时,只有在我尝试添加单个文字但不添加列表时,它才有效.(5:[1,2,3,4])会工作,但([1,2]:[3,4,5])不会.但是有这个功能:
replicate2 n x
| n <= 0 = []
| otherwise = x:replicate2 (n-1) x
Run Code Online (Sandbox Code Playgroud)
我理解这是如何递归地运作,让我们称之为replicate2 2 [1,2]:它将通过第一个后卫,因此:
= [1,2]:replicate (2-1) [1,2]
= [1,2]:[1,2]:replicate (1-1) [1,2]
-- since n is now 0 it's an edge condition and first guard returns [], so recursion ends and we get:
= [1,2]:[1,2]:[]
Run Code Online (Sandbox Code Playgroud)
并且函数返回 [[1,2],[1,2]]
我的问题:这是如何工作的?难道Haskell不应该生气并吐出错误吗?当我尝试在GHCi中这样做时,它会这样做.
好吧,让我们回顾一些事情.运算符的主要(=最一般)类型:是这样的:
(:) :: a -> [a] -> [a]
Run Code Online (Sandbox Code Playgroud)
a是一个类型变量.这一切意味着每次实际使用操作符时,其使用的上下文决定了a在特定用途中将代表什么类型.所以,如果你这样做:
example1 :: [Integer]
example1 = 5 : [1, 2]
Run Code Online (Sandbox Code Playgroud)
......在这方面a是Integer,如果你这样做:
example2 :: [[Integer]]
example2 = [1,2] : [[1,2]]
Run Code Online (Sandbox Code Playgroud)
......那么在这方面a是[Integer].那么类型意味着什么:
(:) :: a -> [a] -> [a]
Run Code Online (Sandbox Code Playgroud)
...是a您在列表头部放置的值的类型必须与进入该列表的值的类型相同.如果它是一个元素为Integers 的列表,那么该值也必须是一个Integer.在一个令你困惑的例子中,我们有一个s 列表列表Integer,因此该:上下文中的第一个参数是一个列表Integer.
Haskell对此非常精确,所以我们可以继续使用其他说明相同原理的例子.例如,我们在列表列表的前面放置一个列表列表:
example3 :: [[[Integer]]]
example3 = [[1, 2], [3, 4]] : [[[1, 2]]]
-- Value: [[[1, 2], [3, 4]], [[1, 2]]]
Run Code Online (Sandbox Code Playgroud)
所以再次回到主要类型::
(:) :: a -> [a] -> [a]
Run Code Online (Sandbox Code Playgroud)
另一种看待它的方式是作为一种模式,:必须遵守所有用法:第一个参数的类型必须比第二个参数和结果的类型少一对方括号.它告诉我们的另一件事是:不关心什么类型a可能 - 它可能是一个简单的值Integer,或者它可能是一些复杂的东西[[[[Integer]]]],而且这个函数无法区分.