Haskell:陷入 IO monad [英] Haskell: Trapped in IO monad
问题描述
我正在尝试使用 haskell-src-exts
包中的 parseFile
函数解析文件.
I am trying to parse a file using the parseFile
function found in the the haskell-src-exts
package.
我正在尝试使用 parseFile
的输出,这当然是 IO
,但我不知道如何绕过 IO代码>.我找到了一个函数
liftIO
但我不确定这是否是这种情况下的解决方案.这是下面的代码.
I am trying to work with the output of parseFile
which is of course IO
, but I can't figure out how to get around the IO
. I found a function liftIO
but I am not sure if that is the solution in this situation. Here is the code below.
import Language.Haskell.Exts.Syntax
import Language.Haskell.Exts
import Data.Map hiding (foldr, map)
import Control.Monad.Trans
increment :: Ord a => a -> Map a Int -> Map a Int
increment a = insertWith (+) a 1
fromName :: Name -> String
fromName (Ident s) = s
fromName (Symbol st) = st
fromQName :: QName -> String
fromQName (Qual _ fn) = fromName fn
fromQName (UnQual n) = fromName n
fromLiteral :: Literal -> String
fromLiteral (Int int) = show int
fromQOp :: QOp -> String
fromQOp (QVarOp qn) = fromQName qn
vars :: Exp -> Map String Int
vars (List (x:xs)) = vars x
vars (Lambda _ _ e1) = vars e1
vars (EnumFrom e1) = vars e1
vars (App e1 e2) = unionWith (+) (vars e1) (vars e2)
vars (Let _ e1) = vars e1
vars (NegApp e1) = vars e1
vars (Var qn) = increment (fromQName qn) empty
vars (Lit l) = increment (fromLiteral l) empty
vars (Paren e1) = vars e1
vars (InfixApp exp1 qop exp2) =
increment (fromQOp qop) $
unionWith (+) (vars exp1) (vars exp2)
match :: [Match] -> Map String Int
match rhss = foldr (unionWith (+) ) empty
(map ((Match a b c d e f) -> rHs e) rhss)
rHS :: GuardedRhs -> Map String Int
rHS (GuardedRhs _ _ e1) = vars e1
rHs':: [GuardedRhs] -> Map String Int
rHs' gr = foldr (unionWith (+)) empty
(map ((GuardedRhs a b c) -> vars c) gr)
rHs :: Rhs -> Map String Int
rHs (GuardedRhss gr) = rHs' gr
rHs (UnGuardedRhs e1) = vars e1
decl :: [Decl] -> Map String Int
decl decls = foldr (unionWith (+) ) empty
(map fun decls )
where fun (FunBind f) = match f
fun _ = empty
pMod' :: (ParseResult Module) -> Map String Int
pMod' (ParseOk (Module _ _ _ _ _ _ dEcl)) = decl dEcl
pMod :: FilePath -> Map String Int
pMod = pMod' . liftIO . parseFile
我只想能够在 parseFile
的输出上使用 pMod'
函数.
I just want to be able to use the pMod'
function on the output of parseFile
.
请注意,所有类型和数据构造函数都可以在 http://hackage.haskell.org/packages/archive/haskell-src-exts/1.13.5/doc/html/Language-Haskell-Exts-Syntax.html 如果有帮助的话.提前致谢!
Note that all the types and data constructors can be found at http://hackage.haskell.org/packages/archive/haskell-src-exts/1.13.5/doc/html/Language-Haskell-Exts-Syntax.html if that helps. Thanks in advance!
推荐答案
一旦进入 IO,就无处可逃.
Once inside IO, there's no escape.
使用fmap
:
-- parseFile :: FilePath -> IO (ParseResult Module)
-- pMod' :: (ParseResult Module) -> Map String Int
-- fmap :: Functor f => (a -> b) -> f a -> f b
-- fmap pMod' (parseFile filePath) :: IO (Map String Int)
pMod :: FilePath -> IO (Map String Int)
pMod = fmap pMod' . parseFile
(addition:) 正如 Levi Pearson 的精彩回答 中所述,还有
(addition:) As explained in great answer by Levi Pearson, there's also
Prelude Control.Monad> :t liftM
liftM :: (Monad m) => (a1 -> r) -> m a1 -> m r
但这也不是黑魔法.考虑:
But that's no black magic either. Consider:
Prelude Control.Monad> let g f = (>>= return . f)
Prelude Control.Monad> :t g
g :: (Monad m) => (a -> b) -> m a -> m b
所以你的函数也可以写成
So your function can also be written as
pMod fpath = fmap pMod' . parseFile $ fpath
= liftM pMod' . parseFile $ fpath
= (>>= return . pMod') . parseFile $ fpath -- pushing it...
= parseFile fpath >>= return . pMod' -- that's better
pMod :: FilePath -> IO (Map String Int)
pMod fpath = do
resMod <- parseFile fpath
return $ pMod' resMod
任何你觉得更直观的(记住,(.)
具有最高优先级,就在函数应用程序的下方).
whatever you find more intuitive (remember, (.)
has the highest precedence, just below the function application).
顺便说一下, >>>= return .f
位是如何 liftM
是实际实现的,只是在do
-notation中;它确实显示了 fmap
和 liftM
的等价性,因为对于任何 monad,它都应该保持:
Incidentally, the >>= return . f
bit is how liftM
is actually implemented, only in do
-notation; and it really shows the equivalency of fmap
and liftM
, because for any monad it should hold that:
fmap f m == m >>= (return . f)
这篇关于Haskell:陷入 IO monad的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!