【问题标题】:Non-Deterministic Merge Sort Doesn't Order Permutations Lexicographically非确定性合并排序不会按字典顺序排列排列
【发布时间】:2016-08-07 09:10:20
【问题描述】:

我一直在尝试复制 Christiansen、Danilenko 和 Dylus 在All Sorts of Permutations (Functional Pearl) 中提到的旁白,这是即将到来的 ICFP 2016 的一篇论文。第 8 节(“最后的评论”)声称通过选择特定的非确定性谓词,一元归并排序可以按字典顺序产生一个序列的所有排列。

我们只考虑了非确定性谓词coinCmp,而还有其他可用于影响枚举顺序的非确定性谓词。例如,以下函数将谓词 cmp 提升到非确定性上下文。

liftCmp :: MonadPlus μ
        ⇒ (α → α → Bool) → Cmp α μ
liftCmp p x y = return (p x y) ⊕ return (not (p x y))

当我们使用该函数提升比较函数并将其传递给合并排序的一元版本时,我们会得到一种特殊的排列函数:它按字典顺序枚举排列。

我很确定我在这里写的是归并排序,但是运行时排序并不像宣传的那样。

import Control.Applicative (Alternative((<|>)))
import Control.Monad (MonadPlus, join)
import Data.Functor.Identity (Identity)

-- Comparison in a context
type Comparison a m = a -> a -> m Bool

-- Ordering lifted into the Boring Monad
boringCmp :: (a -> a -> Bool) -> Comparison a Identity
boringCmp p x y = return (p x y)

-- Arbitrary ordering in a non-deterministic context
cmp :: MonadPlus m => Comparison a m
cmp _ _ = return True <|> return False

-- Ordering lifted into a non-deterministic context
liftCmp :: MonadPlus m => (a -> a -> Bool) -> Comparison a m
liftCmp p x y = let b = p x y in return b <|> return (not b)

mergeM :: Monad m => Comparison a m -> [a] -> [a] -> m [a]
mergeM _ ls         []         = return ls
mergeM _ []         rs         = return rs
mergeM p lls@(l:ls) rrs@(r:rs) = do
    b <- p l r
    if b
    then (l:) <$> mergeM p ls rrs
    else (r:) <$> mergeM p lls rs

mergeSortM :: Monad m => Comparison a m -> [a] -> m [a]
mergeSortM _ []  = return []
mergeSortM _ [x] = return [x]
mergeSortM p xs  = do
    let (ls, rs) = deinterleave xs
    join $ mergeM p <$> mergeSortM p ls <*> mergeSortM p rs
  where
    deinterleave :: [a] -> ([a], [a])
    deinterleave [] = ([], [])
    deinterleave [l] = ([l], [])
    deinterleave (l:r:xs) = case deinterleave xs of (ls, rs) -> (l:ls, r:rs)
λ mergeSortM (boringCmp (<=)) [2,1,3] :: Identity [Int]
Identity [1,2,3]

λ mergeSortM cmp [2,1,3] :: [[Int]]
[[2,3,1],[2,1,3],[1,2,3],[3,2,1],[3,1,2],[1,3,2]]

λ mergeSortM (liftCmp (<=)) [2,1,3] :: [[Int]]
[[1,2,3],[2,1,3],[2,3,1],[1,3,2],[3,1,2],[3,2,1]]

以及实际的字典顺序供参考——

λ sort it
[[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]

【问题讨论】:

  • 如果您将[1,2,3] 作为参数传递会发生什么?
  • 碰巧有效,试试[1..4]

标签: haskell non-deterministic monadplus


【解决方案1】:

让我们尝试deinterleave 的变体,它拆分列表的前半部分和后半部分,而不是像发布的代码中那样拆分偶数和奇数索引元素:

deinterleave :: [a] -> ([a], [a])
deinterleave ys = splitAt (length ys `div` 2) ys

结果:

> mergeSortM (liftCmp (<=)) [2,1,3] :: [[Int]]
[[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]

不幸的是,这并没有像我最初希望的那样解决问题,正如 Rowan Blush 在下面指出的那样。 :-/

【讨论】:

  • 这只是机会,见mergeSortM (liftCmp (&lt;=)) [1,2,3] :: [[Int]][[1,2,3],[2,1,3],[2,3,1],[1,3,2],[3,1,2],[3,2,1]]
  • @RowanBlush 有趣。尽管如此,deinterleave 的定义确实会影响最终结果。我想知道作者使用了哪一个——事实上,是否有一个合理的定义可以真正产生预期的行为。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-06-19
  • 2017-03-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-04-10
相关资源
最近更新 更多