我试着通过例子来理解起重原理,并发现了这一点:
https://github.com/graninas/Functional-Design-and-Architecture/blob/1736abc16d3e4917fc466010dcc182746af2fd0e/First-Edition/BookSamples/CH03/MonadStack.hs
然后,如果我将它的lift (lift (putStrLn "bla-bla"))
更改为putStrLn "bla-bla"
,编译器将抛出错误!
我这样做是基于我理解:do
块只是语法糖,每一行的结果都传递到下一行。如果下一行不使用从上一行传递来的参数,我认为参数的类型不会导致类型冲突。
以下面为例,而x<- getLine
可以通过编译
test:: IO ()
test = do
x <- getLine -- discarded and compiler don't care it type
let a = "bla-bla" -- discarded and compiler don't care it type
putStrLn $ "You type are discarded: "
现在回到calculations
函数:
type Data = Map.Map Int String
type StateIO = StateT Data IO
type MaybeStateIO a = MaybeT StateIO a
calculations :: MaybeStateIO ()
calculations = do
lift (lift (putStrLn "bla-bla")) -- if I change this to `putStrLn "bla-bla"`, it failed compiling.
lift (modify (Map.insert 3 "3"))
lift (modify (Map.insert 1 "1"))
mb <- lift (get >>= (return . Map.lookup 1))
lift (lift (print mb))
main = runStateT (runMaybeT calculations) Map.empty
我不明白的是,对编译器要求在putStrLn "bla-bla"
上进行提升。do
块最后一行的返回值与函数的返回值匹配还不够吗?
在这个例子中,编译器如何根据函数的签名来决定do block
的值类型?
有人能给我解释一下电梯吗?它是如何工作的,什么时候使用等等。
2条答案
按热度按时间3htmauhk1#
do
块最后一行的返回值与函数的返回值匹配还不够吗?不,因为这意味着您可以编写一个
do
块,其中第一项例如将[]
的示例用于Monad
,而下一项将使用例如Maybe
或IO
,但是x <- some_list
对于putStrLn x
的列表有什么意义呢?do
块中的所有行都应该是m a
类型,其中m
是Monad
的同一示例,并且a
的每一行都可以有不同的类型。如果你写一个do块:则将其转换为
exp1 >>= \x -> exp2
,由于(>>=) :: Monad m => m a -> (a -> m b) -> m b
在两个操作数共享相同的一元类型m
的情况下进行操作,因此这意味着exp1 :: m a
和exp2 :: m b
因此需要与相同的一元类型m
一起工作。您需要执行两次提升操作,因为生产线的类型应为
MaybeT (StateT Data IO) a
,而putStrLn "bla-bla"
的类型为IO a
,因此需要一次**lift :: (MonadTrans t, Monad m) => m a -> t m a
**将其提升到StateT Data IO a
,然后再将其最终提升到MaybeT (StateT Data IO) a
。jtw3ybtb2#
calculations
的 值 是 一 个MaybeStateIO
值 , 这 是 你 在 其中 操作 的 单子 , 所以do
块 的 每 一 行 都 要 产生 这个 值 , 但是putStrLn "bla-bla"
并 不 产生MaybeStateIO
值 ;它 只 产生 一 个IO
值 。 第 一 个lift
取 那个IO
值 并 返回 一 个StateIO
值 ;第 二 个lift
采用 该StateIO
值 并 返回 一 个MaybeStateIO
值 。记住 ,
中 的 每 一 个
是
a >> b
的 语法 糖 , 而(>>) :: Monad m => m a -> m b -> m b
需要 来自 同一 个 单子 的 值 作为 参数 , 只有 单子 的 " 返回 值 " (a
和b
) 可以 在 不同 的 行 之间 变化 ;单子m
本身 是 固定 的 。