Честно, не нашёлся, что ответить.
Что мешает нам использовать напрямую класс в ООП и заставляет нас описывать какой-то интерфейс?
Ничего не мешает, это просто удобная абстракция. В частном случае можно вызывать функции. Но это один частный случай.
Насколько я узнал, название идёт из axiom of comprehension, что по-русски обычно переводят как «аксиома выделения». Но «выделение списков» как-то не звучит.
Не понял вопроса. :( Во время вычисления coeval разве не будут производиться side-effecting операции?
Я скорее про «философическую» сторону вопроса.
Обычный IO воспринимается, как World -> (a, World). Т.о. хотя мы в сам World залезть не можем, реализация — может, и putChar можно написать так:
putChar c w@(World (Heap h) ... (Descriptors d)) = case lookup d stdout of
Just f -> Success ((), World (replaceInHeap h f c) ... (Descriptors d))
Nothing -> Exception "hmm..." ((), w)
В комонадах же сначала вызывается enableOI, который дублирует окружение, а затем mapOI, который из функции OI Handle -> Char делает OI (OI Handle) -> OI Char.
Цитата: «The operational effect of co-ext f allows a function f, which accepts arguments that may depend upon the current IO environment, to propagate the IO environment as an implicit parameter along with its result»
где co-ext f = (mapOI f).enableOI
Т.е. некий базовый putChar должен бы иметь тип OI (OI Char) -> OI () и использоваться без mapOI, но тогда неясно, как его использовать внутри своих функций.
Пока писал, подумалось, что Handle может внутри себя содержать все нужные данные (т.е. это не дескриптор, а сами данные), тогда coeval stdin возвращает некоторые данные, а также может выполнить некоторые изменения в окружении (что за изменения — скрыто в реализации OI), а getChar, зная внутреннее устройство Handle достаёт оттуда символ.
Вариант.
Соответственно main будет иметь тип coMain :: OI () -> ()
Вообще, почему-то в Хаскеле монады определяются через return и bind, а не через return, fmap и join
Думаю, в немалой степени из-за do-notation. Там напрямую используются >>= и >>, а так будут лишние действия. Хотя не знаю, будет ли через fmap/join медленнее.
А помоему, довольно понятно: OI Handle -> Char это функция, которая возвращает Char из файла. Это скорее «по-другому» (а так — вполне эстетично).
Я тоже об этом подумал :)
Но тогда можно подумать, что
getChars :: OI Handle -> OI Handle -> (Char, Char)
Возвращает (Char, Char) из двух файлов, а это не так.
Да и OI a обязан быть последним аргументом.
Или я что-то путаю?
Ну т.е. понятно, что getChars f1 f2 = (getChar f1, getChar f2), но как этот getChars в cobind передать?
Честно говоря, не понял я, почему за ними будущее.
У меня есть некоторые претензии/вопросы:
1. Что ни говори, а в чистом языке тип a -> b -> () не может (не должен) иметь побочных эффектов, что бы он там ни принимал
2. Скрытое возвращение результата изменения внешнего мира предлагается делать при помощи mapOI, которая примет функцию f :: OI a -> b, а вернёт f :: OI (OI a) -> OI b. Т.е. f теперь как бы принимает копию окружения и возвращает новую. Но ведь f сам ничего не возвращает, а mapIO ничего не знает об f, следовательно реализация mapOI может разве что скопировать окружение.
3. Теперь все функции с побочными эффектами должны иметь тип OI a -> b, не эстетично
4. IO a имеет вполне понятный смысл — вычисление значения типа a, чего не сказать об OI a -> b
Я даже для State с трудом представляю, как менять этот самый State из функции, а не снаружи при помощи специально написанной local, потому что duplicate всего лишь копирует (о чём я в пункте 2 написал).
Им что, лень добавить лишний проход компилятора, лучше пусть программист мучается?
Во-первых компиляция и так не летает, а во-вторых, сдаётся мне, существует пример, в котором без предварительного объявления выбрать верный путь разбора будет невозможно, хотя я его привести не возьмусь.
Я блог для того и начал, чтобы написать на Хаскеле программу, но для начала надо же дать хоть что-то. Я не ставлю целью рассказать всё, но если при реализации возникнут вопросы, всегда можно посмотреть предыдущую статью, где про это написано. Если всё равно непнонятно, то для более полной информации есть интернет.
Если вас интересует, есть ли вероятность, что darcs провалился из-за ЯП, то да, есть.
Если вы хотите доказать какую-то точку зрения, я бы хотел увидеть как формулировку точки зрения, так и оценку вероятности.
Иначе это выглядит как переливание из пустого в порожнее. Верным может оказаться любое мнение.
Что мешает нам использовать напрямую класс в ООП и заставляет нас описывать какой-то интерфейс?
Ничего не мешает, это просто удобная абстракция. В частном случае можно вызывать функции. Но это один частный случай.
Буду иметь в виду.
Насколько я узнал, название идёт из axiom of comprehension, что по-русски обычно переводят как «аксиома выделения». Но «выделение списков» как-то не звучит.
Я скорее про «философическую» сторону вопроса.
Обычный
IOвоспринимается, какWorld -> (a, World). Т.о. хотя мы в сам World залезть не можем, реализация — может, иputCharможно написать так:В комонадах же сначала вызывается
enableOI, который дублирует окружение, а затемmapOI, который из функцииOI Handle -> CharOI (OI Handle) -> OI CharЦитата: «The operational effect of
co-ext fallows a function f, which accepts arguments that may depend upon the current IO environment, to propagate the IO environment as an implicit parameter along with its result»где
co-ext f = (mapOI f).enableOIТ.е. некий базовый
putCharдолжен бы иметь типOI (OI Char) -> OI ()и использоваться безmapOI, но тогда неясно, как его использовать внутри своих функций.Пока писал, подумалось, что
Handleможет внутри себя содержать все нужные данные (т.е. это не дескриптор, а сами данные), тогдаcoeval stdinвозвращает некоторые данные, а также может выполнить некоторые изменения в окружении (что за изменения — скрыто в реализацииOI), аgetChar, зная внутреннее устройствоHandleдостаёт оттуда символ.Вариант.
Соответственно
mainбудет иметь типcoMain :: OI () -> ()Думаю, в немалой степени из-за do-notation. Там напрямую используются
>>=и>>, а так будут лишние действия. Хотя не знаю, будет ли черезfmap/joinмедленнее.Я тоже об этом подумал :)
Но тогда можно подумать, что
Возвращает
(Char, Char)из двух файлов, а это не так.Да и
OI aобязан быть последним аргументом.Или я что-то путаю?
Ну т.е. понятно, что
getChars f1 f2 = (getChar f1, getChar f2), но как этотgetCharsвcobindпередать?У меня есть некоторые претензии/вопросы:
1. Что ни говори, а в чистом языке тип
a -> b -> ()не может (не должен) иметь побочных эффектов, что бы он там ни принимал2. Скрытое возвращение результата изменения внешнего мира предлагается делать при помощи
mapOI, которая примет функциюf :: OI a -> b, а вернётf :: OI (OI a) -> OI bfтеперь как бы принимает копию окружения и возвращает новую. Но ведьfсам ничего не возвращает, аmapIOничего не знает обf, следовательно реализацияmapOIможет разве что скопировать окружение.3. Теперь все функции с побочными эффектами должны иметь тип
OI a -> b, не эстетично4.
IO aимеет вполне понятный смысл — вычисление значения типаa, чего не сказать обOI a -> bЯ даже для
Stateс трудом представляю, как менять этот самыйStateиз функции, а не снаружи при помощи специально написаннойlocal, потому чтоduplicateвсего лишь копирует (о чём я в пункте 2 написал).Во-первых компиляция и так не летает, а во-вторых, сдаётся мне, существует пример, в котором без предварительного объявления выбрать верный путь разбора будет невозможно, хотя я его привести не возьмусь.
Так что я даже не пытаюсь, просто ещё одно решение.
Важна декларативность чистоты и нечистоты. И когда это выражается на системе типов — выглядит естественно. Хотя можно и ключевое слово ввести.
Ну я бы не говорил «всякие» :)
Помощнее интерфейсов-то будут.
Именно, что данный факт ни о чём не говорит, поэтому и выводов никаких сделать нельзя.
Если вы хотите доказать какую-то точку зрения, я бы хотел увидеть как формулировку точки зрения, так и оценку вероятности.
Иначе это выглядит как переливание из пустого в порожнее. Верным может оказаться любое мнение.