如何使用值对列表[MVar a]进行排序?

时间:2011-08-05 11:39:59

标签: algorithm haskell concurrency

如何对[MVar a]列表进行排序?使用a作为要在排序中进行比较的元素。 E.g:

sortList :: [MVar Int] -> [MVar Int]

如果不打破其他线程,我无法想办法。

更新 我需要对列表进行排序,因为我想实现像MVar这样的引用计数,并且总是返回具有最少引用的引用计数。类似的东西:

getLeastUsed :: [MVar Int] -> MVar Int
getLeastUsed = head . sortList

在线程中我想增加'Int'。

更新 因为MVar

,因为rigth签名需要IO,所以我注意到了

2 个答案:

答案 0 :(得分:8)

首先,你的类型签名是不可能的;阅读MVar并不是引用透明的(希望显而易见的是 - 这就是他们!)。这有两个后果:

  • 您的排序功能必须返回IO操作
  • 列表将根据每个MVar读取时看到的值进行排序;它不仅可能在您使用列表时无效,它可能会在您读取最后一个值之前中途改变,以使第一个值过期。

前者是不可避免的,假设后者对于你的目的是可以接受的,你可以基本上做@hammar所展示的。

但是,鉴于排序很快就会过时,并且您似乎对最小元素感兴趣,您可能会发现这样的东西更直接有用,因为除了排序之外几乎没用:

import Control.Applicative
import Data.List
import Data.Ord

leastUsed :: [MVar Int] -> IO (MVar Int)
leastUsed vars = fst . minimumBy (comparing snd) . zip vars <$> mapM readMVar vars

答案 1 :(得分:5)

最简单的方法可能是做一个decorate-sort-undecorate,你首先读出MVars的所有当前值,然后使用那些作为键进行排序。

import Data.List (sortBy)
import Data.Ord (comparing)

sortList :: [MVar Int] -> IO [MVar Int]
sortList vars = do
    currentValues <- mapM readMVar vars
    return . map snd . sortBy (comparing fst) $ zip currentValues vars

请注意,结果列表可能未完全排序,因为MVars的值自读取后可能已更改。但是,如果您关心这一点,那么您应该在整个列表中使用单个MVar。