Haskell模式匹配:可读性和性能

7
我是一名有用的助手,可以翻译文本。
我正在学习learn you a haskell教程,并且在作者提供的一些示例中遇到了一些问题。
例如,他将zip重新实现如下:
zip' :: [a] -> [b] -> [(a,b)]  
zip' _ [] = []  
zip' [] _ = []  
zip' (x:xs) (y:ys) = (x,y):zip' xs ys

他在所有其他示例中使用相似的方法,即将最具体的模式放在最前面。这是zip函数的稍微不同的版本:
zip' :: [a] -> [b] -> [(a,b)]
zip' (x:xs) (y:ys)  = (x, y):zip' xs ys
zip' _ _            = []

据我所知,这两种方法都是做同样的事情。如果提供了一个空列表,无论是(x:xs)还是(y:ys),都不会匹配,这将通过附加空列表[]来完成递归。
1. 我个人更喜欢第二个版本,因为它更易读,但也许我这么做是错的。 2. 它对方法的性能有任何影响吗?据我所知,如果顶部模式不匹配,Haskell 将检查下一个模式。模式的顺序是否影响性能?
此致敬礼,
编辑: 可能是重复的: Haskell GHC: what is the time complexity of a pattern match with N constructors? 总结:模式的顺序对语义(关于参数的严格评估)和函数的可读性非常重要。模式匹配本身总是在O(1)时间复杂度内完成。

1个回答

7
据我所知,这两种方法的作用是相同的。
几乎一样,但有一个例外:
\> zip' undefined []   -- 1st definition of zip'
[]
\> zip' (filter (< 4) [1..]) [1, 2, 3]
[(1,1),(2,2),(3,3)]

然而:

\> zip' undefined []   -- 2nd definition of zip'
*** Exception: Prelude.undefined
\> zip' (filter (< 4) [1..]) [1, 2, 3]
[(1,1),(2,2),(3,3)   -- gets stuck here; never returns

换句话说,第二个定义总是强制使用弱头归一化形式来处理两个参数。
就性能而言,这意味着可以构造一个病态的例子,使得WHNF涉及重量级计算,因此一个定义的表现与另一个定义非常不同。

3
没错,但是在这两种情况下,zip' undefined [1, 2, 3] 都会导致异常。因此我看不出这有什么帮助或者为什么会令人期望。 - Nima Mousavi
1
@Nimi,在这种情况下,它只确定哪个参数是无条件严格的。 - dfeuer
1
@Nimi,重点在于你可以使这两个函数表现非常不同,而不是做相同的事情。请注意另一个例子 zip' (filter (<4) [1..]) [1, 2, 3],看看它如何影响性能。 - behzad.nouri
@behzad.nouri 啊..我现在看到了。谢谢 - Nima Mousavi

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接