Haskell Monads 和 liftIO 我不明白

pen*_*142 5 monads haskell lifting io-monad scotty

您好社区,感谢您的宝贵时间。

\n

我有一个错误,我不确定错误是什么,但我认为问题是:\n没有从ext-1.2.4.1:Data.Text.Internal.Lazy.Text IO)到 的IO 转换器Web.Scotty.Internal.Types.ScottyT

\n

但我想知道为什么编译器与ext-1.2.4.1:Data.Text.Internal.Lazy.Text IO). 这就是为什么我只使用 String 并删除了所有出现的{-# LANGUAGE OverloadedStrings #-}但仍然收到错误。另一方面,这应该是IO [String],不是吗?\n正如你所提到的,我真的不知道是什么ext-1.2.4.1:Data.Text.Internal.Lazy.Text IO)

\n

在另一个地方,我已经liftIO成功使用了一个a -> IO String函数。我想我也以同样的方式使用它们。

\n

我想我慢慢地感觉到了 monad 是什么,但不太确定。我真的不知道为什么我必须使用一个lift函数。

\n

错误信息:

\n
    \xe2\x80\xa2 No instance for (MonadIO\n                         (Web.Scotty.Internal.Types.ScottyT\n                            text-1.2.4.1:Data.Text.Internal.Lazy.Text IO))\n        arising from a use of \xe2\x80\x98liftIO\xe2\x80\x99\n    \xe2\x80\xa2 In a stmt of a \'do\' block:\n        paths <- liftIO $ getAllFilePaths2 path\n      In the expression:\n        do paths <- liftIO $ getAllFilePaths2 path\n           pathsToScotty paths\n      In an equation for \xe2\x80\x98pathsToScotty2\xe2\x80\x99:\n          pathsToScotty2 path\n            = do paths <- liftIO $ getAllFilePaths2 path\n                 pathsToScotty paths\n   |        \n49 |    paths <- liftIO $ getAllFilePaths2  path\n\n
Run Code Online (Sandbox Code Playgroud)\n

发生错误的地方:

\n
    \xe2\x80\xa2 No instance for (MonadIO\n                         (Web.Scotty.Internal.Types.ScottyT\n                            text-1.2.4.1:Data.Text.Internal.Lazy.Text IO))\n        arising from a use of \xe2\x80\x98liftIO\xe2\x80\x99\n    \xe2\x80\xa2 In a stmt of a \'do\' block:\n        paths <- liftIO $ getAllFilePaths2 path\n      In the expression:\n        do paths <- liftIO $ getAllFilePaths2 path\n           pathsToScotty paths\n      In an equation for \xe2\x80\x98pathsToScotty2\xe2\x80\x99:\n          pathsToScotty2 path\n            = do paths <- liftIO $ getAllFilePaths2 path\n                 pathsToScotty paths\n   |        \n49 |    paths <- liftIO $ getAllFilePaths2  path\n\n
Run Code Online (Sandbox Code Playgroud)\n
import Control.Monad.IO.Class\n...\npathsToScotty2 :: String -> ScottyM ()\npathsToScotty2 path = do\n   paths <- liftIO $ getAllFilePaths2  path\n   pathsToScotty paths\n\n
Run Code Online (Sandbox Code Playgroud)\n

DDu*_*Dub 4

liftIO真正理解 monad 需要时间、练习和耐心,但通过检查类型来理解其需求应该不会太难。

\n

首先, 的类型liftIOMonadIO m => IO a -> m a。这意味着m只要m有 的实例,该函数就可以将任何 IO 操作转换为 monad 中的操作MonadIO。理论上,这只有在m有某种处理IO动作的方式时才能实现,因此该函数将给定的动作嵌入到 monad 中m

\n

您肯定是在正确的地方使用liftIO,那么为什么它不起作用呢?也就是说,您有一个getAllFilePaths2 path类型为 的值IO [String],并且您希望它是一个ScottyM [String]\xe2\x80\x94 类型的值,这确实看起来是一个使用 的好地方liftIO。但是,ScottyM不是实例MonadIO,因为您看到的错误消息试图告诉您,因此您不能使用liftIO.

\n

这可能看起来很疯狂\xe2\x80\x94你真的不能将IO操作嵌入到\ xe2\x80\x94中ScottyM吗?\xe2\x80\x94但这实际上是有充分理由的。IO如果操作抛出错误会发生什么?您的整个网络应用程序崩溃了吗?如果你天真地使用liftIO. 相反,scotty 提供了函数liftAndCatchIO,正如文档所描述的那样,它“类似于liftIO,但捕获任何 IO 异常并将其转换为 Scotty 异常”。IO这是将动作嵌入到 Scotty 中的首选方式。

\n

最后的问题来了:请注意,liftAndCatchIO实际上生成的是 类型的值ActionM a,而不是ScottyM a。此外,无法获取ActionMmonad 中的值并将其放入ScottyMmonad 中。相反,您需要将该值用作操作。所以,我不确定它的pathsToScotty作用是什么,但您很可能需要重写它。

\n