loops - 在 ST monad 内循环
问题描述
我正在尝试在 Haskell 上实现插入排序Data.Array.ST
,并使用一元比较函数。即,sortByM :: (Monad m, Ix i, Enum i, Eq i) => (e -> e -> Ordering) -> STArray s i e -> m (ST s ())
。这是我的代码,用于上下文:
import Data.Ord
import Data.Foldable
import Data.Array.ST
import Control.Monad.ST
sortByM :: (Monad m, Ix i, Enum i, Eq i)
=> (e -> e -> m Ordering)
-> STArray s i e -> m (ST s ())
sortByM cmp xs = sequence_ <$> traverse (bubbleBack xs) [start..end]
where
(start, end) = runST $ getBounds xs
bubbleBack :: (Monad m, Ix i, Enum i, Eq i)
=> STArray s i e -> i -> m (ST s ())
bubbleBack ary = loopM $ fmap (mapLeft runST) . bubbleBackOnce ary
bubbleBackOnce :: (Monad m, Ix i, Enum i, Eq i)
=> STArray s i e
-> i -> m (Either (ST s i) (ST s ()))
bubbleBackOnce ary bubble =
if bubble == start
then return $ Right $ return ()
else do
let elem = runST $ readArray ary bubble
let prev = runST $ readArray ary (pred bubble)
ordering <- cmp elem prev
return $ if ordering == LT
then Left $ do
writeArray ary bubble prev
writeArray ary (pred bubble) elem
return $ pred bubble
else Right $ return ()
-- ...
mapLeft :: (a -> r) -> Either a b -> Either r b
mapLeft f (Left x) = Left (f x)
mapLeft _ (Right x) = Right x
据我了解,我遇到的问题是loopM
' 的第一个参数应该有 type ST s i -> m (Either i (ST s ()))
,但由于runST
' 隐藏ST
内部状态的方法,fmap (mapLeft runST) . bubbleBackOnce ary
有 type (forall s'. ST s' i) -> Either i (ST s i)
。这是我第一次使用 ST,所以我不知道如何解决这个问题。此外,这是一个宠物项目,所以我试图避免依赖现有的可以简化事情的库,例如STMonadTrans。
解决方案
推荐阅读
- php - apache 2.4 无法在全新安装的 Windows 7 64 位上运行
- ruby-on-rails - rails 从 has_many 到 has_many 建立关联引发错误
- wordpress - 列表部分 Wordpress 上的谷歌地图
- google-app-engine - 在 Google Cloud Endpoint 中启用 API 密钥
- javascript - 异步发布第一次尝试失败,第二次有效
- c# - ASP.NET Core 在 Web API 中处理自定义响应/输出格式的方法
- sql - 如何使用最后插入的 ID 在另一个表中插入一行?
- java - 从具有命名歧义的匿名内部类访问封闭方法中的字段的方法
- asp.net - 如何让 ELMAH 登录到 Mongodb?
- json - Jmeter - 如何验证响应 json 的部分