有人能解释一下在 haskell 怎么使用电梯吗?

dsf9zpds  于 2022-11-14  发布在  其他
关注(0)|答案(2)|浏览(135)

我试着通过例子来理解起重原理,并发现了这一点:
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的值类型?
有人能给我解释一下电梯吗?它是如何工作的,什么时候使用等等。

3htmauhk

3htmauhk1#

do块最后一行的返回值与函数的返回值匹配还不够吗?
不,因为这意味着您可以编写一个do块,其中第一项例如将[]的示例用于Monad,而下一项将使用例如MaybeIO,但是x <- some_list对于putStrLn x的列表有什么意义呢?do块中的所有行都应该是m a类型,其中mMonad的同一示例,并且a的每一行都可以有不同的类型。如果你写一个do块:

foo = do
    x <- exp1
    exp2

则将其转换为exp1 >>= \x -> exp2,由于(>>=) :: Monad m => m a -> (a -> m b) -> m b在两个操作数共享相同的一元类型m的情况下进行操作,因此这意味着exp1 :: m aexp2 :: 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

jtw3ybtb

jtw3ybtb2#

calculations 的 值 是 一 个 MaybeStateIO 值 , 这 是 你 在 其中 操作 的 单子 , 所以 do 块 的 每 一 行 都 要 产生 这个 值 , 但是 putStrLn "bla-bla" 并 不 产生 MaybeStateIO 值 ;它 只 产生 一 个 IO 值 。 第 一 个 lift 取 那个 IO 值 并 返回 一 个 StateIO 值 ;第 二 个 lift 采用 该 StateIO 值 并 返回 一 个 MaybeStateIO 值 。
记住 ,

do
   a
   b

中 的 每 一 个
a >> b 的 语法 糖 , 而 (>>) :: Monad m => m a -> m b -> m b 需要 来自 同一 个 单子 的 值 作为 参数 , 只有 单子 的 " 返回 值 " ( ab ) 可以 在 不同 的 行 之间 变化 ;单子 m 本身 是 固定 的 。

相关问题