Я пытаюсь разобрать аргументы программы, используя монады (множественное число). Я хочу построить 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
с лямбдой, которая продолжает анализировать аргументы и данные файла. Значение в результате readFileEither
равно Either String String
. Поскольку результатом parseArgs'
является Either String Parameters
, я хотел бы использовать монадическую привязку Either
для привязки ввода лямбды к parseArgs'
, и все это в рамках монадической привязки IO результата readFileEither
и лямбда.
В моей голове это имеет смысл, но компилятор не согласен.
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)))
Для справки, вот как монадический Either
работает:
instance Monad (Either e) where
return = Right
Left l >>= _ = Left l
Right r >>= k = k r
Что я здесь пропустил? Почему вложенные монадические привязки не проходят проверку типов?