Arhn - архитектура программирования

Понимание монадических привязок во вложенных монадах

Я пытаюсь разобрать аргументы программы, используя монады (множественное число). Я хочу построить 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

Что я здесь пропустил? Почему вложенные монадические привязки не проходят проверку типов?


  • Обратите внимание, что путаницы с вложенными монадами можно избежать, используя эквивалентные преобразователи монад, то есть EitherT e IO a (или более традиционный ErrorT e IO a) вместо IO (Either e a). 22.08.2014
  • @leftaroundabout Я не знал об этих вариантах, я обязательно рассмотрю эти типы! 22.08.2014
  • hlint говорит, что processArgs лучше писать как either (return . Left) parseArgs . enumerateArgs 24.08.2014

Ответы:


1

Проблема здесь просто в том, что вы использовали оператор композиции функций ., но функций для компоновки нет! x >>= (parseArgs' a b) — это прекрасное значение Either, а не функция для его получения. И результатом должно быть значение IO, а не функция Клейсли, чтобы получить такое значение. Вам нужно написать просто return (x >>= (parseArgs' a b)) или, более красиво,

parseArgs (a,b,c) = readFileEither c >>= \x -> return $ x >>= parseArgs' a b
22.08.2014
  • @awashburn, твоя ошибка вполне разумна, ты не идиот. 22.08.2014
  • Новые материалы

    Коллекции публикаций по глубокому обучению
    Последние пару месяцев я создавал коллекции последних академических публикаций по различным подполям глубокого обучения в моем блоге https://amundtveit.com - эта публикация дает обзор 25..

    Представляем: Pepita
    Фреймворк JavaScript с открытым исходным кодом Я знаю, что недостатка в фреймворках JavaScript нет. Но я просто не мог остановиться. Я хотел написать что-то сам, со своими собственными..

    Советы по коду Laravel #2
    1-) Найти // You can specify the columns you need // in when you use the find method on a model User::find(‘id’, [‘email’,’name’]); // You can increment or decrement // a field in..

    Работа с временными рядами спутниковых изображений, часть 3 (аналитика данных)
    Анализ временных рядов спутниковых изображений для данных наблюдений за большой Землей (arXiv) Автор: Рольф Симоэс , Жильберто Камара , Жильберто Кейрос , Фелипе Соуза , Педро Р. Андраде ,..

    3 способа решить квадратное уравнение (3-й мой любимый) -
    1. Методом факторизации — 2. Используя квадратичную формулу — 3. Заполнив квадрат — Давайте поймем это, решив это простое уравнение: Мы пытаемся сделать LHS,..

    Создание VR-миров с A-Frame
    Виртуальная реальность (и дополненная реальность) стали главными модными терминами в образовательных технологиях. С недорогими VR-гарнитурами, такими как Google Cardboard , и использованием..

    Демистификация рекурсии
    КОДЕКС Демистификация рекурсии Упрощенная концепция ошеломляющей О чем весь этот шум? Рекурсия, кажется, единственная тема, от которой у каждого начинающего студента-информатика..