haskell - 理解嵌套 Monad 中的 Monadic 绑定(bind)

标签 haskell compiler-errors monads typeclass haskell-platform

我正在尝试使用单子(monad)(复数)解析程序参数。我想建立一个 IO (Either String Parameters) . Left String表示描述无效参数的错误消息。 Right Parameters表示 doRealWork 所需的有效程序参数.

这是程序的结构:

import System.Environment
import System.IO.Error
data Parameters = Parameters String String [Int]  

main :: IO ()
main = getArgs
   >>= processArgs
   >>= either putStrLn doRealWork

processArgs :: [String] -> IO (Either String Parameters)
processArgs args = (return $ enumerateArgs args)
               >>= (either (return . Left) parseArgs)
                -- This maybe could be improved, but it's not the focus

doRealWork     :: Parameters -> IO ()
doRealWork     = undefined -- I'll implement the real work part later

enumerateArgs  :: [String] -> Either String (String,String,String)
enumerateArgs list
  | length list == 3 = Right (a,b,c) 
  | otherwise        = Left $ "Incorrect Argument Count,\n"
                          ++  "Expected 3 parameters\n"
                          ++  "Received: " ++ show list
  where (a:b:c:[]) = list

readFileEither :: String -> IO (Either String String)
readFileEither = undefined -- it actually works, implementation is irrelevant

parseArgs'     :: String -> String -> String -> Either String Parameters
parseArgs'     = undefined -- it actually works, implementation is irrelevant

parseArgs :: (String,String,String) -> IO (Either String Parameters)
parseArgs (a,b,c) = readFileEither c >>= (\x -> return . (x >>= (parseArgs' a b)))
                          -- IO bind ^^^        Either bind ^^^

正如您在 parseArgs 中看到的那样我想绑定(bind)readFileEither的结果到一个继续解析参数和文件数据的 lambda。 readFileEither 结果中的值是 Either String String .由于 parseArgs' 的结果是 Either String Parameters我想使用 Either的一元绑定(bind)将 lambda 的输入绑定(bind)到 parseArgs' ,所有这些都在 readFileEither 的 IO monadic 绑定(bind)中的结果和 lambda。

在我看来这是有道理的,但编译器不同意。
Couldn't match expected type `IO (Either String Parameters)'
            with actual type `a0 -> c0'
In the expression: return . (x >>= (parseArgs' a b))
In the second argument of `(>>=)', namely
  `(\ x -> return . (x >>= (parseArgs' a b)))'
In the expression:
  readFileEither c >>= (\ x -> return . (x >>= (parseArgs' a b)))

作为引用,monadic Either 作品:
instance Monad (Either e) where
    return = Right
    Left  l >>= _ = Left l
    Right r >>= k = k r

我在这里错过了什么?为什么嵌套的单子(monad)绑定(bind)无法进行类型检查?

最佳答案

这里的问题只是你使用了函数组合运算符 . ,但没有要组合的函数! x >>= (parseArgs' a b)非常好Either值,而不是产生一个的函数。结果应该是 IO值,而不是产生这样一个值的 Kleisli 函数。你需要简单地写return (x >>= (parseArgs' a b)) ——或者,更好的是,

parseArgs (a,b,c) = readFileEither c >>= \x -> return $ x >>= parseArgs' a b

关于haskell - 理解嵌套 Monad 中的 Monadic 绑定(bind),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25452490/

相关文章:

haskell - 为什么 `Concurrently` 不是 Haskell 中的单子(monad)?

haskell - 如何在递归函数中使用 Control.Monad.Cont?

haskell - 返回两个字符串中较长的一个的优雅方式

haskell - 如何从多次运行的 haskell 基准测试中获取更有意义的统计数据

haskell - 既然我们在 GHC 中已经有了 `HasCallStack`,为什么还要提供 `ghc -prof -fprof-auto-top` 机制呢?

haskell - 从可执行文件中查找 ghc 版本

c++ - 错误 C2509 : member function not declared in derived class

c++ - 将字符串对象与 C++ 中的字符串文字进行比较 : why no compile errors?

gcc - 对 libnuma 的 undefined reference

scala - 表达这个 Scala 的更惯用(单子(monad)?)方式