[英]Can some one explain how to use lift in haskell?
我试着通过例子来理解起重原理,发现了这个:
然后,如果我将它的lift (lift (putStrLn "bla-bla"))
更改为putStrLn "bla-bla"
,编译器会抛出错误!
我这样做是基于我的理解: do
块只是语法糖,每一行的结果都传递到下一行。 如果下一行不使用从上一行传递的 args,我认为 args 的类型不会导致类型冲突。
以波纹管为例,而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
的值类型?
谁能帮我解释一下电梯? 它是如何工作的,何时使用等。
calculations
的值是一个MaybeStateIO
值。 这就是你正在操作的 monad,所以这就是do
块的每一行都必须产生的内容。 但是putStrLn "bla-bla"
不会产生MaybeStateIO
值; 它只是产生一个IO
值。 第一个lift
取那个IO
值并返回一个StateIO
值; 第二次lift
采用StateIO
值并返回MaybeStateIO
值。
记住,
do
a
b
只是a >> b
语法糖,并且(>>) :: Monad m => ma -> mb -> mb
需要来自同一个 monad 的值作为参数。 只有单子的“返回值”( a
和b
)会因行而异; monad m
本身是固定的。
do
块最后一行的返回值与函数的返回值匹配还不够吗?
不,因为这意味着您可以编写一个do
块,例如,第一项将使用Monad
的[]
实例,而下一项将使用例如Maybe
或IO
,但是x <- some_list
对putStrLn x
的列表? do
块中的所有行都应该是ma
类型,其中m
是Monad
的相同实例,并且每行a
s 可以有不同的类型。 如果你写一个 do 块:
foo = do x <- exp1 exp2
然后将其转换为exp 1 >>= \x -> exp 2
,并且由于(>>=) :: Monad m => ma -> (a -> mb) -> mb
在两个操作数共享相同的情况下运行monad m
,因此这意味着exp 1 :: ma
和exp 2 :: mb
因此需要使用相同的单子类型m
。
您需要执行两次提升,因为该行应该具有类型MaybeT (StateT Data IO) a
而putStrLn "bla-bla"
具有IO a
,因此需要一次lift :: (MonadTrans t, Monad m) => ma -> tma
将其提升到StateT Data IO a
和另一个最终将其提升到MaybeT (StateT Data IO) a
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.