Хабр Курсы для всех
РЕКЛАМА
Практикум, Хекслет, SkyPro, авторские курсы — собрали всех и попросили скидки. Осталось выбрать!
data Maybe a = Nothing | Just af::Maybe a -> a, выдав значение по умолчанию для Nothing. Это чистые значения.f::IO String действительно может быть какой угодно альтернативой в IO, о которой мы ничего не знаем. Это может быть прочтенная строка с консоли, ошибка, что угодно. Заметим, что мы даже не можем предполагать, что значение с типом IO String это действительно какая то альтернатива IO, нет это всегда одно значение, но оно «многолико». Именно поэтому getLine::IO String это значение (функция без аргументов), которое может «прочесть любую строку с консоли» — прочтенная строка будет строкой/ошибкой/etc для наблюдателя (наблюдатель не находиться в «чистом» мире), в самой программе оперируется чистое значение «все возможные варианты IO» (ключевые: суперпозиция, посыл к квантовой физике)IO или в любом другом «неизвестном типе»/монаде, значит нельзя что либо сделать со значением IO a. Для этого и есть оператор применения >>=, который достает а из монадного значения и применяет ее к функции f::a -> IO a если это возможно. Иначе (если к примеру IO String был ошибкой, а не прочитанной строкой) возвращает новое значение IO a, о котором мы ничего не знаем. Именно потому, что >>= может вернуть IO a «в обход» нашей f, f должна возвращать IO a. Т.е. однажды «испачкавшись» в монадах вы увязли до самого конца программы. В функциональной программе нет времени, т.е. нельзя стать наблюдателем и посмотреть что там в монадном значении (unsafe функции, те которые при «исключительных» значениях «не знают что делать» и оставлены на совесть программисту, мы не рассматриваем. это хак малодушных :), это не Haskell), значит нельзя избавиться от монада. На самом деле программа на Haskell всегда, не зависимо от времени, окружающего мира и т.д. отдает IO (), «многоликое» неизвестное значение, и завершается, мгновенно. После работы программы мы в своем мире с side-effects наблюдаем за полученным значением с типом IO () и видим один из «выпавших» вариантов: вывод на консоль, окошки и т.д. Даже если программа работает несколько суток, общается с пользователем и выкачивает чего из интернета, все равно в «чистом мире» Haskell программа уже отработала и вернула нам IO () со всем что мы видим, можем ввести и можем получить результат обратно. Там нет времени, там нет side-effects :)hasFailed::IO а -> Bool. Но это совсем не хорошо, т.к. из всего «бесконечного» множества вариантов IO a мы вдруг получили Bool, который всегда True | False, не зависимо от действий внешнего мира и времени. Таких функций быть не должно, это unsafe функции. Но может быть hIsClosed::Handle -> IO Bool, применяемая к IO Handle. Тогда логика скрыта в Handle, если там не что-то еще из бесконечного множество «чего то еще». Получил IO Bool мы можем сделать свою логику f::Bool -> IO SomethingElse или дальше катиться в потоке IO SomethingElse. Это может сносить немного крышу. Что бы это понять попробуйте представить, что ваша программа может дать верные результаты или выпасть с ошибками — это все «известные» результаты; либо уборщица шваброй выдернет питание и все накроется — это «не известные» результаты, одно из не подвластных вам проявлений IO SomethingElse. Функциональный мир при этом остается чист и детерминирован.getLine::IO String это всегда одно и то же значение типа IO String, не зависимо от времени или каких либо других сторонних факторов. putStr::String -> IO() всегда возвращает одно и тоже значение типа IO () для одной и той же строки. Выражение:(getLine >>= putStr)::IO ()
Еще Одно Руководство по Монадам (часть 3: Монадные Законы)