Haskell:陷入 IO monad 困境

标签 haskell io monads pure-function

我正在尝试使用 haskell-src-exts 包中的 parseFile 函数解析文件。

我正在尝试使用 parseFile 的输出,这当然是 IO,但我不知道如何绕过 IO。我找到了一个函数 liftIO ,但我不确定这是否是这种情况下的解决方案。下面是代码。

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' 函数。

请注意,所有类型和数据构造函数都可以在 http://hackage.haskell.org/packages/archive/haskell-src-exts/1.13.5/doc/html/Language-Haskell-Exts-Syntax.html 中找到。如果有帮助的话。提前致谢!

最佳答案

一旦进入 IO,就无法逃脱。

使用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 
<小时/>

(添加:)如 great answer by Levi Pearson 中所述,还有

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

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

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

所以你的函数也可以写成

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

无论发现更直观的(请记住,(.) 具有最高优先级,位于函数应用程序下方)

顺便说一下,>>= return 。 f位是如何liftM实际上已实现,仅以 do 表示法实现;它确实显示了 fmapliftM 的等价性,因为对于任何 monad 它都应该包含:

fmap f m  ==  m >>= (return . f)

关于Haskell:陷入 IO monad 困境,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18214664/

相关文章:

haskell - "ignoring (possibly broken) abi-depends field for packages"是什么意思?

c++ - 由于 vector 中的值作为函数参数,程序在编译时失败

C : initializer element is not constant

haskell - 在 State monad 中混合和匹配有状态计算

嵌套 bool 测试的 F# 计算表达式?

haskell - 为什么在使用处理该类型值的函数时不需要导入抽象类型

haskell - 如何在 Haskell 中使元组成为此类的实例?

haskell - 如何声明在 let 中定义的函数的类型

haskell - putStr 和 putStrLn 弄乱了输出

scala - 将 monad 组合成元组运算符 scalaz