函数关于直线对称:“对称”函数的模式(symmetric patterns)

关于函数关于直线对称的问题,在symmetric patterns中经常遇到, 尝试这个新的 stackoverflow 的东西,建议:) 这不是真正的 haskell 特定的,但它在 haskell 中最清楚。

尝试这个新的 stackoverflow 的东西,建议:) 这不是真正的 haskell 特定的,但它在 haskell 中最清楚。

这是一个每隔一段时间出现的模式:一个函数接受两个它对称处理的参数。mappends 经常有这个属性。一个例子:

-- | 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,不重叠产生不变的范围,一个包含在另一个中抛出包含的范围,重叠创建一个合并范围并尝试将其与其余部分合并。

然而,每个案例都有一个镜像变体。因此,即使镜像 4 可以机械地推导出来,最终还是会有 8 个。不仅有两倍的出错空间,由于对称,错误不会被打字者抓住。这种模式有名字吗?一种排除重复的方法?我想我可以试着为一个列表定义它,然后写“mappend a = mconcat [a,b]”。

我想我想做的是“专注”在一个案例上,所以我可以用“这个”和“那个”来写。这不仅比两个同等权限的“r1”和“r2”更容易想到,这个案例应该隐含在这个-那个。

8

诀窍是您要融合两个单独的步骤。第一步只是合并列表。第二个是合并间隔,使它们不重叠。排除两个步骤,一切都简化了。

mergeList (x@(s1,_):xs) (y@(s2,_):ys) = case compare s1 s2 of
      LT -> x : merge xs (y:ys)
      GT -> y : merge (x:xs) ys
      EQ -> x : y : merge xs ys
mergeList xs ys = xs ++ ys
mergeRuns (x@(s1,e1):x'@(s2,e2):xs) 
    | e1 < s2   = x : mergeRuns (x':xs) -- x is less than and nonoverlapping
    | otherwise = mergeRuns ((s1, max e1 e2) : xs) -- there is overlap
mergeRuns x = x
merge xs ys = mergeRuns $ mergeList xs ys

(未经测试)

如果您添加一些内联 pragma,ghc 应该为您生成更多的融合代码。否则,您可以手动融合它们以获得更笨重但更有效的实现。我们的,你可以离开它,因为它应该是相当有效的。

另一种方法是编写一个函数mergeCons :: (n,n) -> [(n,n)] -> [(n,n)](实际上只是mergeRuns的变体),然后将其替换为mergeList函数中的标准缺点。这将使内联的推理更加容易。这里有一些代码演示该解决方案(再次未经测试):

mergeCons x@(s1,e1) (x'@(s2,e2):xs) 
    | e1 < s2   = x : (x':xs) -- x is less than and nonoverlapping
    | otherwise = (s1, max e1 e2) `mergeCons` xs -- there is overlap
mergeCons x [] = [x]
merge' (x@(s1,_):xs) (y@(s2,_):ys) = case compare s1 s2 of
      LT -> x `mergeCons` merge xs (y:ys)
      GT -> y `mergeCons` merge (x:xs) ys
      EQ -> x `mergeCons` y `mergeCons` merge xs ys
merge' xs ys = xs ++ ys
3

不是你的具体情况的解决方案,但在一般的交换函数,你可以在参数上定义一些任意排序,然后让你的函数调用本身与翻转参数,如果他们在“错误”的顺序。

本站系公益性非盈利分享网址,本文来自用户投稿,不代表码文网立场,如若转载,请注明出处

(668)
Abaqus汉化:无法将AbaqusPDE连接到 Abaqus/CAE
上一篇
孕妇胱抑素c偏低:带扬抑符的拉丁文大写字母 'E' (Ò)(e circumflex)
下一篇

相关推荐

发表评论

登录 后才能评论

评论列表(75条)