Monad与Monad变换器

4
"单子允许程序员使用连续的构建块来构建计算",因此它允许我们组合一些计算。如果是这样,那么为什么下面的代码不能运行?
import Control.Monad.Trans.State

gt :: State String String
gt = do
   name <- get
   putStrLn "HI" -- Here is the source of problem!
   put "T"
   return ("hh..." ++ name ++ "...!")


main= do
  print $ execState gt "W.."
  print $ evalState gt "W.."
  • 为什么我们不能将不同的函数放在一个单子中(就像上面的例子)?

  • 为什么我们需要一个额外的层,即变换器来组合单子?

1个回答

8

单子变换器是将不同的函数放入单子中的机制。

单子只知道如何组合那些在该单子能力范围内的计算。你无法在 State 单子中进行 I/O 操作,但你可以在 StateT s IO a 单子中进行。但是,你需要对进行 I/O 操作的计算使用liftIO

import Control.Monad.Trans.State
import Control.Monad.IO.Class (liftIO)

gt :: StateT String IO String
gt = do
   name <- get
   liftIO $ putStrLn "HI"
   put "T"
   return ("hh..." ++ name ++ "...!")


main = do
  print =<< execStateT gt "W.."
  print =<< evalStateT gt "W.."

谢谢你的回答!你能告诉我为什么在最后两行中使用了=<<吗? - 4xx
4
execStateTevalStateT在这里都返回一个IO String,您可能想打印其中的String=<<会使用右侧单子内部的值调用左侧的函数。 - 4castle
@4xx 这个等效版本可能更熟悉您:main = do x <- execStateT gt "W.." ; print x ; y <- evalStateT gt "W.." ; print y - chi
你的回答是针对标准的单子(如IO,State等)还是通用的?我想知道是否可以有一个函数(或单子),在输入上按顺序执行一系列任意函数(计算)? - 4xx

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接