我正在学习一些Haskell,我试图了解模式匹配的工作原理。
在这样做的过程中,我编写了一个简单的nth
函数。
nth' :: Integer -> [a] -> a
nth' n [] = error "Index out of bound"
nth' n (x:xs) = if n == 0 then x else nth' (n - 1) xs
这第一个实现似乎按预期工作。
-- nth' 25 ['a'..'z']
-- 'z'
-- nth' 26 ['a'..'z']
-- *** Exception: Index out of bound
然而,当我重构它用模式匹配替换if语句时,我最终得到了“索引越界”异常,我显然不应该这样做。
nth' :: Integer -> [a] -> a
nth' _ [] = error "Index out of bound"
nth' 0 (x:[]) = x
nth' n (_:xs) = nth' (n - 1) xs
-- nth' 2 ['a'..'z']
-- *** Exception: Index out of bound
我做错了什么?
答案 0 :(得分:13)
模式x:[]
匹配包含一个元素的列表。因此,只有当第一个参数为0且第二个参数是单元素列表时,才会执行nth' 0 (x:[])
个案。如果第二个参数是一个包含多个参数的列表,那么它将进入最后一个案例。
您需要将第二种情况更改为nth' 0 (x:_) = x
,以便无论列表中有多少元素(只要它至少有一个),它就会匹配。
答案 1 :(得分:6)
有问题的条款:
nth' 0 (x:[]) = x
它只匹配一个元素列表。尝试改变它:
nth' 0 (x:_) = x
答案 2 :(得分:1)
尝试:
nth' :: Integer -> [a] -> a
nth' _ [] = error "Index out of bound"
-- nth' 0 (x:[]) = x -- matches one element list x:[] = [x]
nth' 0 (x:_) = x -- matches first element and everything (not just empty list)
nth' n (_:xs) = nth' (n - 1) xs