我一直在为Haskell使用一些资源:了解一下Haskell和wikibook。但是,我很难找到一个解释,帮助我理解递归。我附上了一本代码来自'Learn you a Haskell'一书,我对此有所了解。
maximum' :: (Ord a) => [a] -> a
maximum' [] = error "maximum of empty list"
maximum' [x] = x
maximum' (x:xs)
| x > maxTail = x
| otherwise = maxTail
where maxTail = maximum' xs
我理解上面的所有代码,直到最后一行'maxTail = maximum'xs'。我不明白的是,如何通过调用最大值来评估代码以返回最大值。或者它如何知道最大'是列表中的最高元素。
另一个例子:
reverse' :: [a] -> [a]
reverse' [] = []
reverse' (x:xs) = reverse' xs ++ [x]
了解所有内容,直到在列表的尾部调用reverse'。换句话说,它如何知道反向'意味着反转尾部元素。
我真的很感激解释,并且如果它很简单就道歉,我是这种语言的新手。
答案 0 :(得分:11)
逐行排列,以便您更好地理解它:
1| maximum' :: (Ord a) => [a] -> a
2| maximum' [] = error "maximum of empty list"
3| maximum' [x] = x
4| maximum' (x:xs)
| x > maxTail = x
| otherwise = maxTail
where maxTail = maximum' xs
在第1行:你说你得到一个列表并返回该类型的一个元素。此外,该列表中的元素必须是可以包含的,因此您可以将它们放入订单中。
在第2行:你有一个边缘情况,你说如果你得到一个空列表作为输入,那个空列表中就不会有“最高值”,所以你结束了一个错误的函数。
在第3行:你有另一个边缘情况,你说如果你得到一个包含1个元素的列表,那个元素必须是最高元素,所以你要返回它。
在第4行:您使用模式匹配来匹配第一个元素(x
)和列表的其余部分(xs
)。然后,检查x
是否大于maxTail
,其中maxTail
函数调用maximum'
的结果与列表的其余部分xs
一样。
如果x
大于maxTail
,则返回x
,否则maxTail
大于x
并返回maxTail
。
我认为有一些数字的例子也应该有所帮助:
输入:
[2, 5, 4, 13]
呼叫:
maximum' [2, 5, 4, 13]
会发生什么:
maximum' (x : xs)
↓ ↓
maximum' (2:[5, 4, 13])
│
↓ result 13
x > maxTail = x ↑
2 > maximum' [5, 4, 13] = x //2 > 13 = 13 ← ────┐
│ │
└ maximum' (x : xs) │
↓ ↓ │
maximum' (5:[4, 13]) │
│ │
↓ ↑
x > maxTail = x │
5 > maximum' [4, 13] = x //5 > 13 = 13 ← ─────┐
│ │
└ maximum' (x: xs) │
↓ ↓ │
maximum' (4:[13]) │
│ │
↓ ↑
x > maxTail = x │
4 > maximum' [13] = x //4 > 13 = 13 ┐
│ │
└ maximum' [x] = x ↑
maximum' [13] = 13 → ───────────┘
在你的第二个例子中它几乎是一样的:
1| reverse' :: [a] -> [a]
2| reverse' [] = []
3| reverse' (x:xs) = reverse' xs ++ [x]
在第1行:你说你得到一个列表并返回一个列表。
在第2行:你有一个边缘案例,你说如果你得到一个空列表,反向列表也只是空。
在第3行:您再次使用模式匹配来匹配列表的第一个元素(x
)和它的尾部(xs
)。
现在你只需使用++
将两个列表附加在一起,这是列表中反向尾部的第一个元素。
我希望再举一个例子,它会更清楚一点:
输入:
[1, 2, 3]
呼叫:
reverse' [1, 2, 3]
会发生什么:
reverse' (x : xs)
↓ ↓
reverse' (1:[2, 3])
│ result [3, 2, 1]
↓ ↑
(reverse' [2, 3]) ++ [1] //[3, 2] ++ [1] = [3, 2, 1] ← ────┐
│ │
└ reverse' (x: xs) │
↓ ↓ │
reverse' (2:[3]) │
│ ↑
↓ │
(reverse' [3]) ++ [2] //[3] ++ [2] = [3, 2] ← ───┐ → ┘
│ │
└ reverse' (x:xs) │
↓ ↓ │
reverse' (3:[]) │
│ ↑
↓ │
(reverse' []) ++ [3] //[] ++ [3] = [3] ┐ → ┘
│ ↑
└ reverse' [] = [] → ──────────────────┘
答案 1 :(得分:1)
length' [] = 0
案例1:空列表的长度为0。
length' (x:xs) = 1 + length' xs
案例2:具有至少一个元素的列表的长度比列表尾部的长度多1,我们通过重复案例2找到,直到不再有元素为止,满足案例1。
length' [1, 2, 3]
=
length' (1 : (2 : (3 : [])))
=
1 + length' (2 : (3 : []))
=
1 + (1 + length' (3 : []))
=
1 + (1 + (1 + length' []))
=
1 + (1 + (1 + 0))
=
1 + (1 + 1)
=
1 + 2
=
3
reverse' [] = []
案例1:如果列表为空,则其反向也是空列表。
reverse' (x:xs) = reverse' xs ++ [x]
案例2:如果一个列表至少有一个元素,那么我们可以拉出第一个元素,将其移动到最后,然后以相同的方式反转其余元素 - 通过使用案例2继续列表,直到没有元素保持,满足案例1.
reverse' [1, 2, 3]
=
reverse' (1 : (2 : (3 : [])))
=
reverse' (2 : (3 : [])) ++ [1]
=
reverse' (3 : []) ++ [2] ++ [1]
=
reverse' [] ++ [3] ++ [2] ++ [1]
=
[] ++ [3] ++ [2] ++ [1]
=
[3, 2, 1]
maximum' [x] = x
案例1:如果列表只有一个元素,那么该元素就是最大值。
maximum' (x:xs)
案例2:如果一个列表至少有一个元素,那么......
| x > maxTail = x
......第一个比其他所有人都大,在这种情况下它是最大的;或...
| otherwise = maxTail
......不是,所以最大值是所有其他人中最大的......
where maxTail = maximum' xs
...我们通过在案例2的列表中继续查找,直到只剩下一个元素,满足案例1。
我会重新定义maximum'
的定义,以便更容易地展示它如何替代:
maximum' (x:xs) = let maxTail = maximum' xs in
if x > maxTail then x else maxTail
现在:
maximum' [1, 3, 2]
=
maximum' (1 : (3 : (2 : [])))
=
let maxTail1 = maximum' (3 : (2 : [])) in
if 1 > maxTail1 then 1 else maxTail1
=
let maxTail1 =
(let maxTail2 = maximum' (2 : []) in
if 3 > maxTail2 then 3 else maxTail2) in
if 1 > maxTail1 then 1 else maxTail1
=
let maxTail1 =
(let maxTail2 = 2 in
if 3 > maxTail2 then 3 else maxTail2) in
if 1 > maxTail1 then 1 else maxTail1
=
let maxTail1 = (if 3 > 2 then 3 else 2) in
if 1 > maxTail1 then 1 else maxTail1
=
let maxTail1 = 3 in
if 1 > maxTail1 then 1 else maxTail1
=
if 1 > 3 then 1 else 3
=
3