LINUX.ORG.RU

Монады vs макросы vs фекспры

 , , ,


3

4

Эти все вещи имеют нечто общее — контроль над порядком вычислений. Однако, почему то, я никогда не видел сравнения их с этой точки зрения. Постараюсь восполнить этот пробел, а вы дополните, или возразите. Я привожу градацию в пороядке «от сильного к слабому»

1) fexprs. Имеют полный контроль над вычислениями.

2) macros. Имеют контроль над вычислениями, ограниченный временем компиляции.

3) monads. То же самое, что п. 2, за исключением того, что в теле функции невозможно получить само выражение аргумент, «как он есть», а лишь его вычисленное значение.

Возможно я ошибаюсь, поэтому дополняйте и исправляйте.

Ответ на: комментарий от qnikst

печально.

Да.

пожалуйста, научись читать и выражать свои мысли.

Что именно непонятно?

То, что ты написал ни определение

Не. Через «е».

ни нужно иметь ввиду когда с чем-либо работаешь

Ты слишком мало знаешь про монады, чтобы об этом судить.

это просто информационный шум.

Объясни, пожалуйста, чего ты хочешь. Я уже сказал, что если ты хочешь определений, то можешь их найти в исходниках.

Miguel ★★★★★
()
Последнее исправление: Miguel (всего исправлений: 1)
Ответ на: комментарий от Miguel

Ты слишком мало знаешь про монады, чтобы об этом судить.

ты слишком мало значешь обо мне, чтобы судить об этом.

Объясни, пожалуйста, чего ты хочешь.

нет, ты безнадежен.

qnikst ★★★★★
()
Ответ на: комментарий от anonymous

Отличаются ф-и, которые возвращают IO a - в ракетке они выполняют непосредственно какие-то эффекты (запускаются автоматом), а в хаскеле - это вычисления, котоыре еще нужно запустить.

main запускается автоматом

в ghci вообще все запускаются автоматом.

В твоих терминах можно считать, что программа на Хаскеле возвращает «скомпилированный код» для исполнителя IO. Но любая программа на Racket также возвращает байткод для JIT'а (после выполнения compile, но до выполнения eval). Причём этот байткод даже можно предъявить в отличие от мифического кода для исполнителя IO.

monk ★★★★★
()

забанься уже, унылый anonimous

anonymous
()
Ответ на: комментарий от anonymous

Там есть ф-и, которые в соответствии со спецификацией возвращают вычисление. Но нет ф-й, которые читают/пишут.

Это вопрос терминологии. Можешь считать IO единым потоком ввода/вывода, который требуется как параметр в любую функцию, которая хочет вводить/выводить.

monk ★★★★★
()
Ответ на: комментарий от qnikst

ты слишком мало значешь обо мне, чтобы судить об этом.

Я вижу, что ты пишешь.

нет, ты безнадежен.

То есть, ты сам не знаешь. Ясненько.

Miguel ★★★★★
()
Ответ на: комментарий от monk

Эдакая смесь плюсов интерпретатора

выражения выполняются сразу после чтения

Вообще-то это огромный минус.

fmdw
()
Ответ на: комментарий от monk

В твоих терминах можно считать, что программа на Хаскеле возвращает «скомпилированный код» для исполнителя IO.

Можно.

Но любая программа на Racket также возвращает

Байткод возвращает компилятор, обработав программу на racket, а IO возвращает программа на хаскеле. То есть ИО-терм строит не компилятор (как в случае ракетки), а ты сам, напрямую. У тебя есть возможность превратить значение в терм (return), есть возможность склейки термов (bind), есть библиотечные ф-и, которые возвращают термы (write, read, etc..). Ты генерируешь базовые термы, склеиваешь их нужным тебе образом - получаешь main.

То есть в обычном языке ты пишешь код и компилятор по строгим правилам его компилирует, получая машкод/байткод, в языке с макросами ты можешь дергать какие-то апи компилятора. В хаскеле ты сам вместо компилятора отдаешь команды, что, как и когда сгенерировать. Само по себе ничего не генерится.

anonymous
()
Ответ на: комментарий от monk

Можешь считать IO единым потоком ввода/вывода

Считать, что IO - некоторое представление cfg (тем более что это так и есть на самом деле) гораздо естественнее, чем считать, будто ф-и таскают туда-сюда вселенную.

anonymous
()
Ответ на: комментарий от anonymous

Считала моя программа на лиспе квантмех неделю^W год (потому что на лиспе), и наконец насчитала. С радостью хочет она вывести в логи "Done!", но в этой строке кто-то забыл закрыть скобочку. И весь год машинного времени теряется в одно мгновенье.

fmdw
()
Ответ на: комментарий от Miguel

Ты можешь видеть, что угодно, может быть даже можешь это понять.

Я 10 раз написал, но ты или не понял, или проигнорировал, какой мне смысл писать 11тый? На вопросы заданные тебе ответов бы я лучше не видел, зачем мне продолжать? Так что никакого смысла в продолжении беседы с тобой я не вижу. Тем более в том, в чем я был совсем не прав - меня убедили (твоей заслуги в этом, к слову, нет).

qnikst ★★★★★
()
Последнее исправление: qnikst (всего исправлений: 1)
Ответ на: комментарий от fmdw

С радостью хочет она вывести в логи «Done!», но в этой строке кто-то забыл закрыть скобочку. И весь год машинного времени теряется в одно мгновенье.

Тебе какбы сразу укажет что скобка не закрыта и программа не запустится.

anonymous
()
Ответ на: комментарий от anonymous

Наткнулись на любое выражение при чтении файла, выполнили. После этого читаем следующее выражение (или не читаем, если при выполнении произошла ошибка). Эдакая смесь плюсов интерпретатора (выражения выполняются сразу после чтения)

?

fmdw
()
Ответ на: комментарий от qnikst

Честно говоря, чувак, я тебя тоже не совсем понимаю. Тут только anonimus высказал, что понимает тебя, и я нахожу это весьма тревожным знаком.

hateyoufeel ★★★★★
()
Ответ на: комментарий от anonymous

Считать, что IO - некоторое представление cfg (тем более что это так и есть на самом деле) гораздо естественнее, чем считать, будто ф-и таскают туда-сюда вселенную.

Почему?

hateyoufeel ★★★★★
()
Ответ на: комментарий от anonymous

Тебе какбы сразу укажет что скобка не закрыта и программа не запустится.

$ cat testr.lisp
(format t "ok~%")

(format t "done"

$ sbcl
* (load "testr")
ok

debugger invoked on a SB-C::INPUT-ERROR-IN-LOAD in thread
#<THREAD "main thread" RUNNING {ACD37A1}>:
  READ error during LOAD:

    end of file on #<SB-SYS:FD-STREAM
                     for "file /home/monk/languages/lisp/test/testr.lisp"
                     {AF01CF9}>

    (in form starting at line: 1, column: 17, file-position: 17)

Обрати внимание, ok выполнился и вывелся.

monk ★★★★★
()
Ответ на: комментарий от fmdw

И весь год машинного времени теряется в одно мгновенье.

Нет. Лисп запустит отладчик и предложит в этой точке что-нибудь сделать. Вон даже на космическом корабле http://nmp.jpl.nasa.gov/ds1/ ошибку в программе удалённо исправляли не останавливая программу.

monk ★★★★★
()
Ответ на: комментарий от fmdw

Ну тебе при чтении скажет, что скобочки нет. И вообще пример надуманный - тот факт что скобка не закрыта тебе еще редактор подсветит.

anonymous
()
Ответ на: комментарий от hateyoufeel

Потому что, очевидно, НА САМОМ ДЕЛЕ функции не могут гонять вселенную туда-сюда. С другой стороны, гонять представление CFG они вполне могут, несложно написать подобную реализацию. Более того - в реальности именно этим они и занимаются, то есть IO является некоторым куском cfg, представленным машкодом.

Ну и крмое того кога ты видишь writeln «1» >> writeln «2», то горазо удобнее понимать это как «взяли вычисление выводящее 1 и приклеили к нему вычисление выводящее 2, получили вычисление, выводящее 1, потом 2», чем «где-то там в потрохах прилетел мир, который мы както суем туда-сюда».

anonymous
()
Ответ на: комментарий от monk

А, там под программой подразумевался список топлевел форм. Ну тогда да. Но на самом деле я не могу представить в реальности ошибку подобного рода.

anonymous
()
Ответ на: комментарий от anonymous

Потому что, очевидно, НА САМОМ ДЕЛЕ функции не могут гонять вселенную туда-сюда.

С точки зрения системы типов, функции именно это и делают, хоть это и хак. А в остальном я с тобой согласен, да.

hateyoufeel ★★★★★
()
Ответ на: комментарий от anonymous

Считать, что IO - некоторое представление cfg (тем более что это так и есть на самом деле) гораздо естественнее, чем считать, будто ф-и таскают туда-сюда вселенную.

Я же говорю, вопрос субъективен. Вон в Clean явно пишут

Start:: *World -> *World
Start w = …

monk ★★★★★
()
Ответ на: комментарий от monk

Ну ладно. Тогда другой пример. Написали прошивку круиз-контроля для грузовика на лиспе и опять-таки забыли скобочку. Хочешь, значит, затормозить, и тут лисп запускает отладчик и предлагает что-нибудь сделать.

fmdw
()
Ответ на: комментарий от anonymous

Потому что, очевидно, НА САМОМ ДЕЛЕ функции не могут гонять вселенную туда-сюда.

Посмотри, как IO устроено в каком-нибудь mercury.

fmdw
()
Ответ на: комментарий от anonymous

А, там под программой подразумевался список топлевел форм.

В Common Lisp других нет.

Но на самом деле я не могу представить в реальности ошибку подобного рода.

При наличии тестирования — да. Но в при написании одноразовых программ (типы вычислительной математики и физики) вполне можно и облажаться. Другое дело, что это не смертельно — дебаггер спасает.

monk ★★★★★
()
Ответ на: комментарий от fmdw

Написали прошивку круиз-контроля для грузовика на лиспе

В этом случае 100% будет тестирование, причём полностью покрывающее код. Так что не только скобочку, но и простые ошибки логики не должны попасть в рабочую версию. Или, думаешь, настоящий программист сам себе прошивает машину и тут же на ней едет?

monk ★★★★★
()
Последнее исправление: monk (всего исправлений: 1)
Ответ на: комментарий от hateyoufeel

он тоже не понимает. Смысл в том, что категорийная структура «монада» является минимальной структурой, позволяющей делать цепочку из монадических действий, т.е. действий, в которых одно действие зависит от результата другого. В свою очередь само API класса Monad, естественным образом позволяет не использовать данное свойства используя только свойства более слабых структур, что было продемонстрировано в данном треде.

Во всяких «what monad is not», обычно это приводится для «So while it is correct to say that monads can be used to order operations, it would be wrong to say that monads are a mechanism for ordering operations.», я говорил, что для варианта без создания порядка тот факт, что данная структура данных является монадой не нужно. (впрочем сильно подозреваю, что это не верное утверждение, но у с приведением опровержения у оппонентов плоховато будет).

qnikst ★★★★★
()
Ответ на: комментарий от hateyoufeel

С точки зрения системы типов, функции именно это и делают

Нет. С точки зрения системы типов у нас есть некое IO a и вопрос в том, чем его моделировать. Можно считать что IO a = State a World, а можно считать, что IO a = Syntax a

Второй вариант лучше просто тем, что:

1. он семантически ближе к тому, как собственно оно все работает на самом деле

2. при желании мы действительно может реализовать такую модель «в лоб», она будет работать корректно, мы сможем посмотреть, например, реализацию бинда - и там будет обычный код, который совершенно обычным и понятным образом модифицирует обычный и понятный граф. То есть все ясно - что, как, почему, до мельчайших нюансов.

С другой стороны, если мы посмотрим на бинд в первой модели, то увидим там, как тягается какой-то непонятный World - что это значит? А если у меня World изменится, то это что, отслаивание паралеллньой вселенной? Что вообще и как?

То есть получится, что объяснение нифига не объясняет низлежащих процессов и выполняет исключительно формальные функции.

anonymous
()
Ответ на: комментарий от qnikst

является минимальной структурой, позволяющей делать цепочку из ... действий, в которых одно действие зависит от результата другого

А почему не простая композиция? f(g(h(x))) или f $ g $ h.

monk ★★★★★
()
Ответ на: комментарий от monk

Угу, учитывая, что функция является чистой, каждое выполнение программы, с точки зрения семантики, создает новую реальность. Большой взрыв по нажатию кнопки! :)

anonymous
()
Ответ на: комментарий от fmdw

Написали прошивку круиз-контроля для грузовика на лиспе и опять-таки забыли скобочку. Хочешь, значит, затормозить, и тут лисп запускает отладчик и предлагает что-нибудь сделать.

Такого не бывает, просто прими это как факт. Это возможность сугубо теоретическая.

anonymous
()
Ответ на: комментарий от qnikst

Смысл в том, что категорийная структура «монада» является минимальной структурой, позволяющей делать цепочку из монадических действий, т.е. действий, в которых одно действие зависит от результата другого.

«может» - не значит «должен». Если мы МОЖЕМ написать монаду, которая так работает, это не значит, что любая монада должна так работать.

я говорил, что для варианта без создания порядка тот факт, что данная структура данных является монадой не нужно.

Так для последовательности действий монада тоже не нужна, достаточно >>: m a -> m b -> m b

anonymous
()
Ответ на: комментарий от anonymous

каждое выполнение программы, с точки зрения семантики, создает новую реальность

Так оно и создает. Реальность на момент окончания программы. Которая отличается от реальности до программы побочными эффектами внесёнными программой и изменениями не зависящими от программы.

monk ★★★★★
()
Ответ на: комментарий от anonymous

Нет. С точки зрения системы типов у нас есть некое IO a и вопрос в том, чем его моделировать. Можно считать что IO a = State a World, а можно считать, что IO a = Syntax a

С точки зрения системы типов IO a = ST RealWorld a. Здесь (https://github.com/dterei/Research-Papers/blob/master/To Read/Lazy functional...) этот подход, собственно, и описан. Детали за 20 лет могли слегка поменяться, но суть осталась та же.

hateyoufeel ★★★★★
()
Ответ на: комментарий от monk

А почему не простая композиция? f(g(h(x))) или f $ g $ h.

Язык ленивый, у тебя что угодно в этой композиции может быть выполнено когда угодно. Если только записать все вложенные формы через `seq`, но это именно то, что, в итоге, делает бинд.

anonymous
()
Ответ на: комментарий от hateyoufeel

С точки зрения системы типов IO a = ST RealWorld a.

Я же говорю, это лишь _один_ из вариантов. Напишу IO a = ST RealWorld a, будет так. Напишу IO a = Syntax a, будет так. Отличие в том, что для второго случая можно задать реализацию, а для первого - нет.

anonymous
()
Ответ на: комментарий от monk

Так оно и создает.

Оно ее меняет, in-place.

Реальность на момент окончания программы.

Только оно ее делает из старой. А должно - оставлять старую нетронутой и делать новую :)

Вот захотел кто-то вывести hello world! - изволь скопировать анонимуса, monk'a, да и весь лор в придачу :)

anonymous
()
Ответ на: комментарий от anonymous

«может» - не значит «должен». Если мы МОЖЕМ написать монаду, которая так работает, это не значит, что любая монада должна так работать.

в общем-то я говорю о том, что монада это минимальная сущность в которой мы это МОЖЕМ делать. Наверное, если я сильно упорюсь, то я смогу даже сформулировать более-менее корректную формулировку в отношении эффектов, но я не вижу смысла, тем более, что это не будет опровержением точку зрения оппонентов.

Так для последовательности действий монада тоже не нужна, достаточно >>: m a -> m b -> m b

абсолютно точно не нужна, аппликативного функтора (*>) хватит, говорить, что m это монада

qnikst ★★★★★
()
Ответ на: комментарий от anonymous

И что, там world гоняют, как в Clean?

Именно.

Где этот world хранится, можно узнать?

Грубо говоря, мир = оперативка. Но поскольку она историю всех своих изменений не хранит, обращение дважды к одной ссылке приведёт к фигне:

world' = print world "foo"
world'' = print world "bar" // Time paradox!

В Clean и mercury для избежания этого придуман костыль под названием uniqueness types. Т.е. два раза использовать значение переменной нельзя, потому что низя.

Монады решают проблему двойного обращения по ссылкам без лишних сущностей: из них просто эти ссылки фиг выковыришь. Так что да, функции таскают за собой мир.

fmdw
()
Ответ на: комментарий от qnikst

Так погоди:

в общем-то я говорю о том, что монада это минимальная сущность в которой мы это МОЖЕМ делать.

Но дальше:

абсолютно точно не нужна, аппликативного функтора (*>) хватит

Очевидно, что оба эти утверждения не могут быть истинны одновременно. Что неверно?

anonymous
()
Ответ на: комментарий от qnikst

и как мне unsafePerformIO поможет выдернуть значение из QnikstMonad?

Я думал, мы конкретно об IO говорим.

anonymous
()
Ответ на: комментарий от hateyoufeel

Честно говоря, чувак, я тебя тоже не совсем понимаю. Тут только anonimus высказал, что понимает тебя, и я нахожу это весьма тревожным знаком.

Не только. Я тоже прекрасно понимаю qnikst. И тоже хочу увидеть решение поставленной проблемы.

anonymous
()
Ответ на: комментарий от fmdw

Грубо говоря, мир = оперативка.

Не, не катит, у тебя тогда мир меняется без воздействия программы, сам по себе.

Монады решают проблему двойного обращения по ссылкам без лишних сущностей: из них просто эти ссылки фиг выковыришь.

Ну да, только бинд написать нельзя без «расковыривания».

Так что да, функции таскают за собой мир.

Но в релаьности они за собой никакой мир не таскают, это чисто формалистсккий выебон на уровне «ну если самообмануться и считать так, то ...»

anonymous
()
Ответ на: комментарий от monk

В этом случае 100% будет тестирование

То есть средствами языка эта проблема не решается, нужны люди-тестировщики. Так и запишем.

fmdw
()
Ответ на: комментарий от anonymous

ну потерян конкекст же:

Смысл в том, что категорийная структура «монада» является минимальной структурой, позволяющей делать цепочку из монадических действий, т.е. действий, в которых одно действие зависит от результата другого.

applicative позволяет написать последовательность действий с эффектами. но applicative не задает порядок их выполнения, т.к. второе действие не зависит от результатов первого. Т.е. в applicative (a *> b) никто не запрещает сначала применить эффект b, потом a, в отличии от.

qnikst ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.