问题
while the following code:
postImportR = do
fi <- lookupFiles "file"
fc <- lift $ fileSource (fi !! 0) $$ consume
seems to work (at least can I "liftIO $ print fc), splitting it off to a function for iterating doesn't:
process :: [FileInfo] -> [String]
process [] = []
process (f:r) = do
fn <- fileName f
fc <- lift $ fileSource f $$ consume
([fn] : (process r))
postImportR = do
fi <- lookupFiles "file"
process fi
or even with a lambda function:
files <- L.map (\f -> (fileName f, lift $ fileSource f $$ consume)) fi
in the Handler it gives me a type error I don't understand.
Where's my fault -- liked to generate content for database import from the file's lines (and to learn some more Haskell, of course).
回答1:
You have
fileName :: FileInfo -> Text
so you can't directly use fileName
in a do-block like
fn <- fileName f
That would need to be a let-binding
let fn = fileName f
The next thing is what makes process :: [FileInfo] -> [String]
impossible(1),
fileSource :: FileInfo -> Source (ResourceT IO) ByteString
so with
fc <- lift $ fileSource f $$ consume
you are in a do-block whose Monad
is a MonadIO
, and you can't get out of a Monad
that can wrap arbitrary IO
-actions, just like you can't get out of IO
itself.
What you can have is
process :: (SomeFiendishConstraint m) => [FileInfo] -> m [Text]
process [] = return []
process (f:r) = do
let fn = fileName f
lift $ fileSource f $$ consume
fs <- process r
return (fn : fs)
or, more succinctly,
process = mapM (\f -> lift $ fileSource f $$ consume >> return fileName f)
and then
postImportR = do
fi <- lookupFiles "file"
process fi
(1) Barring unsafePerformIO
.
来源:https://stackoverflow.com/questions/14855617/yesod-handlers-content-of-posted-files