【问题标题】:Understanding Monadic Binds in Nested Monads理解嵌套 Monad 中的 Monadic 绑定
【发布时间】:2014-10-16 15:08:27
【问题描述】:

我正在尝试使用单子(复数)解析程序参数。我想建立一个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 中看到的,我想将readFileEither 的结果绑定到一个继续解析参数和文件数据的lambda。 readFileEither 的结果中的值是 Either String String。由于parseArgs' 的结果是Either String Parameters,我想使用Either 的单子绑定将lambda 的输入绑定到parseArgs',所有这些都在readFileEither 的结果的IO 单子绑定中和拉姆达。

这在我的脑海中是有道理的,但编译器不同意。

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

我在这里错过了什么?为什么嵌套的 monadic 绑定无法进行类型检查?

【问题讨论】:

  • 请注意,通过使用等效的 monad 转换器,可以在很大程度上避免与嵌套 monad 的混淆,即 EitherT e IO a(或更传统的 ErrorT e IO a)而不是 IO (Either e a) .
  • @leftaroundabout 我不知道这些选项,我一定会研究这些类型!
  • hlintprocessArgs 最好写成either (return . Left) parseArgs . enumerateArgs

标签: haskell compiler-errors monads typeclass haskell-platform


【解决方案1】:

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

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

【讨论】:

  • @awashburn,你的错误是完全合理的,你不是白痴。
猜你喜欢
  • 1970-01-01
  • 2023-04-09
  • 2019-04-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多