有状态循环与不同类型的休息

jak*_*iel 5 monads haskell state-monad monad-transformers

我试图将以下有状态命令代码转换为Haskell.

while (true) {
  while (get()) {
    if (put1()) {
      failImmediately();
    }
  }
  if (put2()) {
    succeedImmediately();
  }
}
Run Code Online (Sandbox Code Playgroud)

无论是put1put2读取系统的状态,并对其进行修改.get可以简单地读取状态.failImmediately应该突破无限循环并呈现一种结果,succeedImmediately也应该突破却呈现出不同的结果.

我试图用是State Env Result其中Env代表环境的状态,Result是像Either Failure Success一些定制FailureSuccess.

我挣扎着要求整个结果表达式应该崩溃到Failure/ Success一旦它们中的一个产生(打破循环),否则继续前进.

我有一个想法是利用Either Exit ()地方data Exit = Success | Failure和使用StateT某种方式在表现Left对的Either,就好像Either是被链接的单子,也就是忽略任何后续行动.

我真的很感激haskell代码的任何灵感或样本,它将实现与上面的代码片段相同的行为.

编辑:精炼版移动到一个单独的问题" 有不同类型的短路的状态计算(可能,或者) ".

Cac*_*tus 6

使用来自@ chi答案的套件,只需突出显示您不需要全部功能ContT,直接短路语义EitherT就足够了:

import Control.Monad.Trans.Either

data Result a = Failure | Success a

foo :: EitherT (Result Int) IO Int
foo = forever $ do
    whileM get $ do
        whenM put1 $ do
            left Failure
    whenM put2 $ do
        left $ Success 42

run :: (Monad m) => EitherT (Result a) m a -> m (Maybe a)
run act = do
    res <- runEitherT act
    return $ case res of
        Left Failure -> Nothing
        Left (Success x) -> Just x
        Right x -> Just x

-- whenM / whileM and get/put1/put2 as per @chi's answeer
Run Code Online (Sandbox Code Playgroud)