我正在尝试使用单子(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/