2

您好社区感谢您的时间。

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

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

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

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

错误信息:

    • No instance for (MonadIO
                         (Web.Scotty.Internal.Types.ScottyT
                            text-1.2.4.1:Data.Text.Internal.Lazy.Text IO))
        arising from a use of ‘liftIO’
    • In a stmt of a 'do' block:
        paths <- liftIO $ getAllFilePaths2 path
      In the expression:
        do paths <- liftIO $ getAllFilePaths2 path
           pathsToScotty paths
      In an equation for ‘pathsToScotty2’:
          pathsToScotty2 path
            = do paths <- liftIO $ getAllFilePaths2 path
                 pathsToScotty paths
   |        
49 |    paths <- liftIO $ getAllFilePaths2  path

发生错误的地方:

import Control.Monad.IO.Class
...
pathsToScotty2 :: String -> ScottyM ()
pathsToScotty2 path = do
   paths <- liftIO $ getAllFilePaths2  path
   pathsToScotty paths

getAllFilePaths2 :: String -> IO [String]
getAllFilePaths2 dir = do
    putStrLn dir
    isFile <- doesFileExist dir 
    if isFile 
        then return [dir] 
        else do
          dirs <- listDirectory dir
          foldl foldHelper2 (return []) $ map (\d -> show $ mconcat [dir, "/",d ]) dirs


foldHelper2 :: IO [String] -> String  -> IO [String]
foldHelper2 ps path = do 
    paths <- ps
    newPaths <- getAllFilePaths2 path
    return (paths ++ newPaths)

4

1 回答 1

3

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

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

你绝对是在正确的地方使用liftIO,那为什么它不起作用呢?也就是说,你有一个getAllFilePaths2 pathtype的值IO [String],并且你希望它是一个 type 的值ScottyM [String]——这确实是一个使用的好地方liftIO。但是,ScottyM不是的实例,因为MonadIO您看到的错误消息试图告诉您,所以您不能使用liftIO.

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

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

于 2021-02-04T14:27:42.373 回答