Hello community thank you for your time.
I have an error and I am not sure what the error is, but what I think the problem is:
There is no IO transformer from ext-1.2.4.1:Data.Text.Internal.Lazy.Text IO) to Web.Scotty.Internal.Types.ScottyT.
But I wondering why the compiler works with ext-1.2.4.1:Data.Text.Internal.Lazy.Text IO). That's why I am working just with String and I removed all occurrences of {-# LANGUAGE OverloadedStrings #-} but still get the error. On the other hand, this should be IO [String], shouldn't it?
And as you can mention I don't really know what ext-1.2.4.1:Data.Text.Internal.Lazy.Text IO) is.
At another place, I already use liftIO successfully for an a -> IO String function. And I think I use them the same way.
I think I get slowly a feeling for what a monad is, but not quite sure. I don't really know why I have to use a lift function at all.
Error message:
• 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
Where the error occurred:
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)
Truly understanding monads takes time, practice, and patience, but it shouldn't be too hard to understand the need for
liftIOby examining your types.First off, the type of
liftIOisMonadIO m => IO a -> m a. This means that the function can convert any IO action into an action in the monadmso long asmhas an instance ofMonadIO. In theory, this can only be implemented ifmhas some way of processingIOactions, so this function is embedding the given action into themmonad.You're definitely in the right sort of place to use
liftIO, so why isn't it working? That is, you have a valuegetAllFilePaths2 pathof typeIO [String], and you'd like it to be a value of typeScottyM [String]— this indeed seems like a good place to useliftIO. However,ScottyMis not an instance ofMonadIO, as that error message you saw is trying to tell you, so you can't useliftIO.This may seem crazy—can you really not embed IO actions into
ScottyM?—but there's actually a good reason for this. What happens if theIOaction throws an error? Does your whole web app crash? It would if you naively usedliftIO. Instead, scotty provides the functionliftAndCatchIO, which, as the docs describe, is "LikeliftIO, but catch any IO exceptions and turn them into Scotty exceptions." This is the preferred way to embedIOactions into Scotty.And here comes the final gotcha: Note that
liftAndCatchIOactually produces values of typeActionM a, notScottyM a. Additionally, there's no way to take a value in theActionMmonad and get it into theScottyMmonad. Instead, you need to use that value as an action. So, I'm not sure whatpathsToScottydoes, but it's very likely that you'll need to rewrite it.