gpt4 book ai didi

Haskell:为什么这个 monad 转换是错误的?

转载 作者:行者123 更新时间:2023-12-02 12:48:32 24 4
gpt4 key购买 nike

我正在研究 monad 转换器,我读了 this SO帖子关于如何避免lift s。

我的想法是MonadIO是单子(monad),其中 IO可以嵌入,并且 MonadWriter w是单子(monad),其中 WriterT w可以嵌入。所以我写了下面的代码(读取、累积和记录数字,直到得到零),其中使用显式 lift 的工作版本是在评论中。但 GHC 却提示道。我做错了什么?

{-# LANGUAGE FlexibleContexts #-}
import Control.Monad.IO.Class
import Control.Monad.Writer.Class (MonadWriter)
import Control.Monad.Trans.Reader
import Control.Monad.Trans.Writer

-- f :: ReaderT Int (WriterT [String] IO) Int
-- m1 = ReaderT, m2 = WriterT
f :: (MonadWriter [String] m1, MonadIO m2) => m1 (m2 (IO Int))
f = do
s <- liftIO getLine
tell ["Input: " ++ s] -- lift $ tell ["Input: " ++ s]
let i = read s :: Int
if i == 0
then ask
else local (+i) f

main = do
rst <- runWriterT $ runReaderT f 0
print rst

最佳答案

My thought was that MonadIO are monads in which IO can be embedded, and MonadWriter w are monads in which WriterT w can be embedded.

这并不完全正确。 MonadIO 可以使用 liftIOMonadWriter可以使用tell。因此,如果您想在同一上下文/monad 中使用 liftIOtellasklocal 而无需 lift ,您使用的单个 monad 必须是所有这些 monad 的实例:

f :: ( MonadWriter [String] m -- monad supports  tell   :: [String] -> m ()
, MonadReader Int m -- monad supports ask :: m Int
, MonadIO m -- monad supports liftIO :: IO a -> m a
) => m Int -- only a single m

请注意,您不能使用transformer,而是使用mtl来实现自动提升。因此,导入也会发生变化:

import Control.Monad.Reader (runReaderT, MonadReader)
import Control.Monad.Writer (runWriterT, MonadWriter)
import Control.Monad.IO.Class (liftIO, MonadIO)

MonadIO 的导入不会改变,因为 IO 操作永远不会自动取消。

顺便说一句,您使用 runWriterTrunReaderT 已经消除了变压器堆栈的所有歧义,因为这将使用

ReaderT Int (WriterT [String] IO Int)

关于Haskell:为什么这个 monad 转换是错误的?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35864153/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com