3

用一些数据来做我State'的程序状态。

type State' m a = StateT Int m a

我会在一些计算中使用它。

例子:

-- genData, return some string (using Int value and State')
genData :: Int -> State' String
genData n = ...

-- genDatas, return multiple strings
genDatas :: Int -> State' [String]
genDatas n = mapM genData [1..n]

-- printLog, write log message (enumerating lines)
printLog :: String -> State' IO ()
printLog msg = do
  n <- get
  let n' = n + 1
  put n'
  liftIO $ putStrLn $ "Message #" ++ (show n') ++ ": " ++ msg

我认为这不是正确的方法:

-- If I need a "in context function" returning a Int value...
--
-- addExtra, return current Int in state plus x
addExtra :: Int -> State' Identity Int
addExtra x = get >>= return.(+x)

addExtra在某些 monad 上下文中使用我的函数,我会这样做:

doComplex :: State' IO ()
doComplex = do
  printLog "Starting process..."

  -- It's ugly!
  s <- get
  Identity (w, s') <- return $ runStateT (addExtra 5) s
  put s' -- save state

  printLog $ "computed value: " ++ (show w)

沿着不同功能共享我的State'monad 的正确方法是什么?(就像IO a做的那样)

谢谢!

(我已经阅读了一些教程和一些源代码,但我无法理解)

4

1 回答 1

5

回答你的问题

由于您的addExtra函数实际上并没有对底层 monad 做任何事情,因此您只需更改类型签名以使其与 monad 无关:

addExtra :: Monad m => Int -> State' m Int
addExtra x = get >>= return . (+x)

现在你可以写这个

doComplex :: State' IO ()
doComplex = do
    printLog "Starting process..."

    w <- addExtra 5

    printLog $ "Computed value: " ++ show w

哪个更漂亮,并且就像您的旧代码一样工作:

*Main> runStateT doComplex 0
Message #1: Starting process...
Message #2: Computed value: 6
((),2)

在旁边

我可能很想重写addExtra以下内容之一。首先,要么使用 do 表示法

addExtra x = do s <- get
                return (s + x)

或使用liftM,因为我们并没有真正使用我们有一个单子的事实

addExtra x = liftM (+x) get

甚至使用gets(感谢评论中的 Daniel Wagner)

addExtra x = gets (+x)

当然,此时您可能不需要附加功能。你也可以写

doComplex = do printLog "Starting process..."
               w <- gets (+5)
               printLog $ "Computed value: " ++ show w

同样,我可能会重写printLog. 如果您发现自己get对状态进行了操作,对其进行了操作并将put其返回,那么您可能只想使用modify.

printLog msg = do modify (+1)
                  n <- get
                  liftIO . putStrLn $ "Message #" ++ show n ++ ": " ++ msg
于 2012-10-31T11:38:05.883 回答