尝试使用这个新的stackoverflow,如建议的:) 这并不是特定于haskell的,但在haskell中最清晰。
这里有一个模式,偶尔会出现:一个函数接受两个参数,并对它们进行对称处理。 mappend经常具有此属性。 一个例子:
-- | Merge sorted lists of ranges.
merge :: (Ord n) => [(n, n)] -> [(n, n)] -> [(n, n)]
merge [] r2 = r2
merge r1 [] = r1
merge r1@((s1, e1) : rest1) r2@((s2, e2) : rest2)
| e1 < s2 = (s1, e1) : merge rest1 r2
| e2 < s1 = (s2, e2) : merge r1 rest2
| s1 >= s2 && e1 <= e2 = merge rest1 r2 -- 1 within 2
| s2 >= s1 && e2 <= e1 = merge r1 rest2 -- 2 within 1
| e1 > e2 = merge (merged : rest1) rest2
| otherwise = merge rest1 (merged : rest2)
where merged = (min s1 s2, max e1 e2)
请注意,对'r1'和'r2'的处理是对称的。实际上只有4种情况:与null合并产生非null范围,不重叠范围保持不变,一个包含在另一个中的子范围会被舍弃,重叠会产生合并范围并尝试将其与其他范围合并。然而,每个情况都有镜像变体,因此最终有8种情况,即使可以通过机械推导得出这4种情况的镜像。不仅容易犯错,由于对称性,类型检查器也无法捕捉错误。这种模式有没有名称?有没有一种方法来消除这种重复?我想我可以尝试为列表定义它,然后写'mappend a b = mconcat [a, b]',但是对于我来说,问题的一般形式相当困难(例如,我很难想象应将合并后的间隔放回哪个列表)。定义mappend然后获取mconcat要容易得多。也许有一种更好的方法来考虑列表版本,以避免头部受伤?我觉得我想做的是“聚焦”于一种情况,这样我就可以用“这个”和“那个”来表述。这比在两个同等权限的'r1'和'r2'中思考要容易得多,那->这种情况应该隐含在这个->那个情况中。