我正在学习Haskell,我无法理解这个功能。我正在实施mergesort。我实现了mergesort递归函数,但我不明白这个'merge'函数在做什么。我理解命令式语言中的合并排序,但我不理解这里的语法。
merge [] ys = ys
merge xs [] = xs
merge xs@(x:xt) ys@(y:yt) | x <= y = x : merge xt ys
| otherwise = y : merge xs yt
答案 0 :(得分:12)
merge [] ys = ys
如果第一个参数为空,则给出第二个参数。
merge xs [] = xs
如果第二个参数为空,则给出第一个参数。
merge xs@(x:xt) ys@(y:yt) | x <= y = x : merge xt ys
| otherwise = y : merge xs yt
如果x
小于或等于y
,请将(添加到前面)x合并到xs
的其余部分(xt
)ys
。否则y
较小,因此将xs与ys
的其余部分(yt
)合并后的结果。
xs@(x:xt)
是使用“占位符”的参数解构。结果是xs
将引用整个第一个参数,而x
是头部,xt
是尾部。
由于合并是递归定义的,它将继续使用xs和ys中的元素,直到至少有一个为空,然后简单地返回它。
条形图(|)表示"guards",它允许您以简洁明了的方式定义条件。
答案 1 :(得分:3)
让我们逐行打破这个:
merge [] ys = ys
此行模式与第一个列表匹配。如果第一个列表是空列表(即[]
),则返回第二个列表。
merge xs [] = xs
与之前相同,只是反对列表角色。
merge xs@(x:xt) ys@(y:yt)
仅当list元素非空时,类似(x:xt)
的模式匹配才匹配。如果匹配x
设置为第一个元素,则xt
设置为列表的其余部分。请记住:
是列表构造函数运算符(即1 : [2, 3] == [1, 2, 3]
)。
xs@...
前缀表示整个列表设置为xs
。如果您需要同时参考整个列表及其头部和尾部,这将非常有用。
答案 2 :(得分:2)
函数模式匹配它的两个参数。让我们看看每个条款:
merge [] ys = ys
因此,合并空列表和另一个列表y会导致ys。
merge xs [] = xs
这就像第一个子句,反过来说:合并列表xs和空列表给出了xs。
merge xs@(x:xt) ys@(y:yt) | x <= y = x : merge xt ys
| otherwise = y : merge xs yt
这是递归子句。这里函数模式匹配它的两个参数,因此:
xs
是第一个列表,并且被解构(通过as-pattern)到头部x
和尾部xt
ys
是第二个列表,它被解构为头部y
,它的尾部为yt
。现在,如果第一个列表的头部小于或等于第二个列表的头部(第一个保护),则结果只是第一个列表y
的头部,后面是合并的结果第一个列表的尾部(这是xt
)和第二个列表ys
。如果y
小于x
,我们会相反。