【问题标题】:How to apply stateful computation to a list?如何将有状态计算应用于列表?
【发布时间】:2015-10-02 13:54:33
【问题描述】:

让我们想象一个 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,但我无法理解它,而且感觉这不是正确的方法......)

【问题讨论】:

    标签: haskell state-monad


    【解决方案1】:

    您可以从Data.Foldable 使用traverse_

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

    【讨论】:

    • 工作正常!谢谢 !仍然需要了解许多概念。
    【解决方案2】:

    您要查找的函数是sequence,它具有签名sequence :: Monad m =&gt; [m a] -&gt; m [a],是处理State 等单子时非常常见的模式。

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

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

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

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

    【讨论】:

    • sequence . map ftraverse f 相同,但后者的类型更通用。
    【解决方案3】:

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

    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
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-08-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-08-02
      • 1970-01-01
      相关资源
      最近更新 更多