Haskell:陷入IO monad [英] Haskell: Trapped in IO monad

查看:103
本文介绍了Haskell:陷入IO monad的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图使用haskell-src-exts包中的parseFile函数解析文件。我正在尝试使用parseFile的输出,这当然是IO,但我无法弄清楚如何绕过IO。我发现了一个函数liftIO,但我不确定这是否是这种情况下的解决方案。这是下面的代码。

  import Language.Haskell.Exts.Syntax 
import Language.Haskell.Exts
import Data.Map隐藏(foldr,map)
导入Control.Monad.Trans

increment :: Ord a => a - >映射Int - >映射一个Int
增量a = insertWith(+)a 1

fromName :: Name - >字符串
fromName(Ident s)= s
fromName(Symbol st)= st

fromQName :: QName - >字符串
fromQName(Qual_fn)= fromName fn
fromQName(UnQual n)= fromName n
$ b $ 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 (应用e1 e2)= unionWith(+)(vars e1)(vars e2)
vars(Let _ e1)= vars e1
vars(NegApp e1)= vars e1
vars(Var qn)=增量(来自QName qn)空
变量(Lit l)=增量(fromLiteral l)空
变量(Paren e1)=变量e1
变量(InfixApp exp1 qop exp2)=增量(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字符串Int
rHs'gr = foldr(unionWith(+))empty(map(\(GuardedRhs abc) - > vars c)gr)

rHs :: Rhs - > ;映射字符串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模块) - > Map String Int
pMod'(ParseOk(Module _ _ _ _ _ _ dEcl))= decl dEcl

pMod :: FilePath - > Map String Int
pMod = pMod'。 liftIO。 parseFile

我只想在parseFile的输出中使用pMod'函数。请注意,所有类型和数据构造函数都可以在 http://hackage.haskell.org/packages/archive/haskell-src-exts/1.13.5/doc/html/Language-Haskell-Exts-Syntax.html <如果这有帮助。提前致谢!



使用 fmap

   -  parseFile :: FilePath  - > IO(ParseResult模块)
- pMod'::(ParseResult模块) - > 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的出色答案所解释的那样,还有

  Prelude Control.Monad> :t liftM 
liftM ::(Monad m)=> (a1→r)→> m a1 - > m r

但是这也不是什么黑魔法。考虑:

  Prelude Control.Monad>让g f =(>> = return。f)
Prelude Control.Monad> :t g
g ::(Monad m)=> (a - > b) - > m a - > mb

所以你的函数也可以写成

  pMod fpath = fmap pMod'。 parseFile $ fpath 
= liftM pMod'。 parseFile $ fpath
=(>> = return。pMod')。 parseFile $ fpath - 推送它...
= parseFile fpath>> = return。 pMod' - 这是更好的

pMod :: FilePath - > IO(Map String Int)
pMod fpath = do
resMod< - parseFile fpath
return $ pMod'resMod

不管找到更直观的(记住,(。)具有最高优先级,就在函数应用程序的下面)



顺便说一句,>> => return。 f 位是 liftM 实际上只是在 do -notation;它确实显示了 fmap liftM 的等价性,因为对于任何monad,它都应该保持:

  fmap fm = m>> =(return。f)


I am trying to parse a file using the parseFile function found in the the haskell-src-exts package. 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 

I just want to be able to use the pMod' function on the output of parseFile. 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!

解决方案

Once inside IO, there's no escape.

Use 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:) 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).

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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆