История изменений
Исправление Macil, (текущая версия) :
Вот я и спрашиваю — где?
Знамо где. В рантайме, который совсем-совсем не чистый, и написан на C.
Если про Monad — то, как я уже писал, внутри µ. Только чистого µ как такового нет.
Наверное, основная причина непонимания работы Monad лежит в том, что когда начинающие смотрят на (>>=) :: m a → (a → m b) → m b
, то думают что результирующий m b делает левая часть (f :: a → m b
т.е.), а bind ee просто возвращает, но на самом деле, результирующий m b делает именно bind. Т.е. запускает некий runFoo :: m a → a
для левой части, затем в зависимости от результата передает полученное значение в свою левую часть, еще раз запускает runFoo и оборачивает полученное значение в m через какой-то из комбинаторов a → m b
(не обязательно return). Если один из bind в цепочке не будет вычислять свою левую часть, то цепочка вычислений прервется.
Цепочка вычислений, она не совсем цепочка. Как и список, она напоминает луковицу (a >>= (\a' → b >>= (\b' → c >>= (\c' → ...))))
, где bind сдирает очередной слой. Собственно, do-нотация и есть просто удобная запись вышеприведенного.
Можно придумать хитрый комбинатор, который будет противоположен bind, т.е. вычислять свою левую часть, когда bind ее не вычисляет. С помощью него можно организовать «обработку исключений».
Можно пойти дальше, и в качестве a использовать функцию... Что дает много интересных эффектов. Например, можно организовать несколько «точек выхода» http://www.scs.stanford.edu/11au-cs240h/notes/parsing-slides.html
PS: И да, бытует мнение что runIO не существует. Это мнение неправильное. Если он недоступен, как и конструктор IO, это не значит что его нет.
Исходная версия Macil, :
Вот я и спрашиваю — где?
Знамо где. В рантайме, который совсем-совсем не чистый, и написан на C.
Если про Monad — то, как я уже писал, внутри µ. Только чистого µ как такового нет.
Наверное, основная причина непонимания работы Monad лежит в том, что когда начинающие смотрят на (>>=) :: m a → (a → m b) → m b
, то думают что результирующий m b делает левая часть (f :: a → m b
т.е.), а bind ee просто возвращает, но на самом деле, результирующий m b делает именно bind. Т.е. запускает некий runFoo :: m a → a
для левой части, затем в зависимости от результата передает полученное значение в свою левую часть, еще раз запускает runFoo и оборачивает полученное значение в m через какой-то из комбинаторов a → m b
(не обязательно return). Если один из bind в цепочке не будет вычислять свою левую часть, то цепочка вычислений прервется.
Цепочка вычислений, она не совсем цепочка. Как и список, она напоминает луковицу (a >>= (\a' → b >>= (\b' → c >>= (\c → ...))))
, где bind сдирает очередной слой. Собственно, do-нотация и есть просто удобная запись вышеприведенного.
Можно придумать хитрый комбинатор, который будет противоположен bind, т.е. вычислять свою левую часть, когда bind ее не вычисляет. С помощью него можно организовать «обработку исключений».
Можно пойти дальше, и в качестве a использовать функцию... Что дает много интересных эффектов. Например, можно организовать несколько «точек выхода» http://www.scs.stanford.edu/11au-cs240h/notes/parsing-slides.html
PS: И да, бытует мнение что runIO не существует. Это мнение неправильное. Если он недоступен, как и конструктор IO, это не значит что его нет.