如何使用IO比较功能对列表进行排序?
sortWith :: [String] -> (String -> String -> IO Ordering) -> IO [String]
Sortby期待(a->a->Ordering)
,我不知道,如何处理它。我懒得自己快速排序。
答案 0 :(得分:15)
我担心没有简单的方法。如果可以解除
sortBy :: Ord a => (a -> a -> Ordering) -> [a] -> [a]
到
sortByM :: (Ord a, Monad m) => (a -> a -> m Ordering) -> [a] -> m [a]
您可以在sortBy
的实施中看到比较顺序,违反参照透明度。
一般来说,从xxxM
到xxx
很容易,但反过来却不容易。
可能的选择:
unsafePerformIO
作为黑客切换到按键排序并使用Schwartzian transform
sortOnM :: (Monad m, Ord k) => (a -> m k) -> [a] -> m [a]
sortOnM f xs = liftM (map fst . sortBy (comparing snd)) $
mapM (\x -> liftM (x,) (f x)) xs
答案 1 :(得分:3)
sortBy
函数使用合并排序作为GHC中的算法,但Haskell 98报告规定应使用插入排序。
为简单起见,因为我没有编译器所以无法测试我的代码,所以我将在这里实现插入排序:
import Data.Foldable (foldrM)
insertByM :: (a -> a -> IO Ordering) -> a -> [a] -> IO [a]
insertByM _ x [] = return [x]
insertByM cmp x ys@(y:ys') = do
p <- cmp x y
case p of
GT -> do
rest <- insertByM cmp x ys'
return $ y : rest
_ -> return $ x : ys
sortByM :: (a -> a -> IO Ordering) -> [a] -> IO [a]
sortByM cmp = foldrM (insertByM cmp) []
正如我所说,我没有测试过这段代码,但它可以/应该可以工作。
答案 2 :(得分:1)
哦,我以前做过这个!使用monadic比较器合并排序:
type MComparator m a = a -> a -> m Ordering
sortByM :: (Monad m, Functor m) => MComparator m a -> [a] -> m [a]
sortByM cmp [] = return []
sortByM cmp [x] = return [x]
sortByM cmp xs = do
let (ys, zs) = partition xs
ys' <- sortByM cmp ys
zs' <- sortByM cmp zs
merge ys' zs'
where merge [] bs = return bs
merge as [] = return as
merge (a:as) (b:bs) = do
comparison <- cmp a b
case comparison of
LT -> (a:) <$> merge as (b:bs)
_ -> (b:) <$> merge (a:as) bs
partition xs = splitAt (length xs `quot` 2) xs
来自我的博文:http://unknownparallel.wordpress.com/2012/07/03/using-monadic-effects-to-reverse-a-merge-sort/
答案 3 :(得分:-3)
Larry Wall是不是说懒惰是程序员的三大优点之一?
似乎您想将类型(a - &gt; a - &gt; b)的函数转换为类型(a - &gt; a - &gt; c b)的函数。我们将其插入Hoogle。现在,如果你知道IO是Monad,你会在liftM2中看到第10场比赛。检查(liftM2 sortBy)的类型,这是你想要的吗?