如何将有状态计算应用于列表?

时间:2015-10-02 13:54:34

标签: haskell state-monad

让我们想象一下Brainf * ck的虚拟子集:

+递增计数器

-递减计数器

一个简单的程序:

program = "++++--" -- should evaluate to 2

有状态评估功能:

eval :: Char -> State Int Char
eval '+' = do x <- get
              put (x + 1)
              return 'I'
eval '-' = do x <- get
              put (x - 1)
              return 'D'

您如何评价该计划? (对我来说看起来像fold但是我无法理解它,并且它感觉不是正确地做到这一点......)

3 个答案:

答案 0 :(得分:7)

您可以使用traverse_中的Data.Foldable

import Data.Foldable (traverse_)
execState (traverse_ eval "++++--") 0

答案 1 :(得分:5)

您要查找的功能是sequence,其签名为sequence :: Monad m => [m a] -> m [a],在处理State等单子时非常常见。

对于您的代码,您希望评估者看起来像这样:

evalBF :: String -> State Int String
evalBF = sequence . map eval

然后您可以使用以下内容进行全面评估:

main :: IO ()
main = do
       src <- getLine
       print $ runState (evalBF src) 0

答案 2 :(得分:1)

一个丑陋的解决方案,但使用您正确怀疑的折叠是适用的。

import Control.Monad.Trans.State

program = "++++--"

eval :: Char -> State Int Char
eval '+' = do
    x <- get
    put (x + 1)
    return 'I'
eval '-' = do
    x <- get
    put (x - 1)
    return 'D'

evalList :: [Char] -> State Int Char
evalList = foldl (\s c -> (s >> eval c)) (return ' ')

main = putStrLn $ show $ runState (evalList program) 0