LINUX.ORG.RU

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

 , , ,


3

4

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

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

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

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

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

Ответ на: комментарий от terminator-101

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

О боже ж ты мой, да ты же дебил! Чувак, монады в хаскелле написаны на хаскелле. Ты волен написать свой собственный Prelude, в котором не будет монад.

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

Хаскель - это метаязык для ИО,

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

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

О боже ж ты мой, да ты же дебил!

А ты быстрый. Весь остальной ЛОР это понял месяцы назад.

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

вычисление будет ровно то той степени, чтобы обеспечить правильную цепочку.

Ну это нам обещает разработчик компилятора, а мы верим. В самом хаскеле об этом ничего не сказано, какая угодно может быть цепочка. И монады ничего не гарантируют.

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

Настолько же лисп является метаязыком для машинных кодов.

Нет, лисп является метаязыком для самого себя. В лиспе мы на лиспе пишем ф-и, генерирующие код на лиспе.

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

Это тут при чем? Смысл в том, что сам хаскель не делает ничего кроме как генерации терма main. Для удобства можешь считать что этот терм - некая строка с кодом на питоне. А кто там будет дальше выполнять этот код на питоне - не дело хаскеля. И все ИО - они не в хаскеле, а в питоне. То есть ф-я getLine хаскеля возвращает строку «input();», например, функция putStr принимает строку х и возвращает новую строку «print(x);» и так далее.

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

сам хаскель не делает ничего кроме как генерации терма main. Для удобства можешь считать что этот терм - некая строка с кодом на питоне.

сам лисп не делает ничего кроме генерации байткода (clisp) или машинных кодов (sbcl). Думаю не сильно сложнее сделать компиляцию в питон.

Это тут при чем?

Ты же почему-то отрываешь от хаскела ввод/вывод (IO). Ну так лисп с оторванным вводом/выводом (stream) умеет не больше.

monk ★★★★★
()

Ничего не понял.

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

Дело не в этом. Лисп, в случае метациклического исполнителя, служит сам себе виртуальной машиной. Лисп крутится на самом лиспе.

terminator-101
() автор топика
Ответ на: комментарий от qnikst

Бывает.

Для тупых: контрпример опровергает утверждение. Всегда.

То, что контрпример обладает некими специальными свойствами («выражается через appicative») никак на это не влияет. Вообще никак.

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

сам лисп не делает ничего кроме генерации байткода (clisp) или машинных кодов (sbcl).

Не так. Терм на лиспе после вычисления совершает какие-то эффекты, например (disaplyln 10) выводит на печать «10» и возвращает void. Терм на хаскеле не совершает и не может совершать никаких эффектов, то есть putStr «10» возвращает «print(10);» и ничего не делает больше.

Ты же почему-то отрываешь от хаскела ввод/вывод (IO).

Я его не отрываю, его там изначально нет. Нету в хаскеле ф-й, которые могут делать ввод/вывод, есть ф-и, которые возвращают ВЫЧИСЛЕНИЕ, которое уже само если его запустить (например через eval, он же unsafePerformIO) этот ввод/вывод сделает. Понимаешь разница между ф-ей f, которая выводит строку, и ф-ей g, которая возвращает код, который выведет строку при своем запуске? Вот в хаскеле только такие как g, существование таких как f запрещено семантикой.

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

Ну ты же умный человек, ну.

qnikst много раз сказал, что особенность монады нужно смотреть в сравнении с Applicative. Какой смысл мутить Monad, у которого ограничений сильно больше, чем у Applicative, если он не даст ничего нового?

Вот и встаёт резонный вопрос. Чего именно такого даёт Monad в сравнении с Applicative? qnikst утверждает, что это порядок вычислений. Пока контрпримеров именно к этому утверждению не было.

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

Это уже детали реализации, которые могут быть различны.

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

Итак, вы выбрали пункты 1 и 3. С криком «докажите, что я неправ!» вы бросаетесь в атаку. Из всех разбойников не сдал позицию только тот, что в шляпе.

Однако перед позорным бегством из треда девочка-волшебница успела призвать Летающего Макаронного Монстра, который изнасиловал нашего героя своими щупальцами. Будете переигрывать?

fmdw
()

Возможно я ошибаюсь

Батюшки, у него что - ремиссия?

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

Терм на хаскеле не совершает и не может совершать никаких эффектов

Терм «main = putStr „Hello!“» совершает. Или ты будешь утверждать, что это не терм Хаскела? Или что он не выведет Hello! при выполнении?

ВЫЧИСЛЕНИЕ, которое уже само если его запустить (например через eval, он же unsafePerformIO)

В лисп аналогично. #'(disaplyln 10) — это вычисление, которое уже само если его запустить (например через eval) этот ввод/вывод сделает.

В лисп каждая топ-левел форма выполняется через eval. В Haskell топ-левел форма в таком смысле одна и у неё есть имя main.

А для «ф-ей g, которая возвращает код, который выведет строку при своем запуске» есть Template Haskell.

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

В Haskell топ-левел форма в таком смысле одна и у неё есть имя main.

Не знаю, что вы называете «топ-левел формой» но в haskell (GHC) их может быть сколько угодно, ибо unsafePerformIO.

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

но в haskell (GHC) их может быть сколько угодно, ибо unsafePerformIO

Напиши пример программы на Хаскелле, которая выполнит putStr «Test» не через main.

monk ★★★★★
()
Ответ на: комментарий от fmdw
$ cat test.hs
foo :: Int
foo = unsafePerformIO $ putStrLn "Test" >> return 42

$ ghc test.hs
[1 of 1] Compiling Main             ( test.hs, test.o )

test.hs:2:7: Not in scope: `unsafePerformIO'

$ vi test.hs
$ cat test.hs
import Foreign

foo :: Int
foo = unsafePerformIO $ putStrLn "Test" >> return 42

$ ghc test.hs 
[1 of 1] Compiling Main             ( test.hs, test.o )

test.hs:1:1: The function `main' is not defined in module `Main'

Не работает. Это не программа на Haskell.

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

Для тупых^W^W перефразирую себя - монады для sequencing, для всего остального что приведено в примерах монады не нужны и их свойства используются никак. Ну использовали вы аппликативный функтор Maybe ну и дальше что? Мы кажется о монадах.

На самом деле правильно звучала бы фраза, что монады детерминируют последовательность эффектов, надеюсь это у вас хватит ума не оспаривать?

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

42. Предложу таблеток анимешной девочке, перефразирую утверждение и останусь стоять дальше.

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

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

In functional programming, a monad is a structure that represents computations defined as sequences of steps: a type with a monad structure defines what it means to chain operations, or nest functions of that type together. This allows the programmer to build pipelines that process data in steps, in which each action is decorated with additional processing rules provided by the monad.[1] As such, monads have been described as «programmable semicolons»; a semicolon is the operator used to chain together individual statements in many imperative programming languages

Эта очевидная вещь никогда не будет *понята*, так как это означало бы отказ от илитизма. Хотя все самоочевидно даже для человека, далекого от фп

terminator-101
() автор топика
Ответ на: комментарий от terminator-101

не, не. они правы в том, что а). из-за ленивости часть действий может быть не выполнена б). порядок редукции тоже не опеределен. Последнее моё уточнение стоит очень далеко от того, что я говорил сначала.

Энергичность - это противовес ленивости, поэтому и убирается она соотвествующими методами: 1). seq (плюс сахар через BangPatterns) 2). в ML - case, ничего общего с монадами. В принципе ничего не мешает ввести Strict монаду, которая будет все форсить в бинде, но зачем?

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

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

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

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

монады для sequencing

https://www.haskell.org/haskellwiki/What_a_Monad_is_not#Monads_are_not_about_...

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

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

bind - создает последовательность эффектов.

Мы опять к этому возвращаемся. Не все монады выражают какие-либо эффекты. Плюс из-за lazy evaluation правая часть (>>=) может вычислиться раньше левой или одновременно с ней. Мы же сейчас о порядке вычислений говорим?

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

Я «согласился» с тем, что я был неправ в том как сформулировал утверждение сначала. Я не знаю или это по тому, что я привык к laziness или поспорить хотелось.

Сейчас мы только об эффектах.

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

Сейчас мы только об эффектах.

Можно по-точнее? Identity из MTL, например, не имеет никаких эффектов.

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

монады для sequencing

Нет.

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

И что?

Ну использовали вы аппликативный функтор Maybe ну и дальше что?

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

монады детерминируют последовательность эффектов,

Это чушь. Только к монадам IO и STM (ну и к их производным) это в какой-то мере относится.

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

Мы использовали монаду Maybe.

нет, ты не использовал ни одного свойства которые дают монады, Если так судить то ты использовать Storable Maybe, но это ни отностится к суди проблемы никак.

Maybe это тип данных, это не монада, не аппликативный функтор, не функтор. Говорить то, что maybe это монада, ты можешь говорить тогда и только тогда ты используешь операцию относительно которой он является монадой, т.е. когда ты используешь bind.

Это чушь. Только к монадам IO и STM (ну и к их производным) это в какой-то мере относится.

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

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

Только к монадам IO и STM (ну и к их производным) это в какой-то мере относится.

ST, Cont, Maybe, State, STM, Either, LogicT, список продолжать? Пока только (->) (без local) и Identity выпали..

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

Терм «main = putStr „Hello!“» совершает. Или ты будешь утверждать, что это не терм Хаскела?

putStr «Hello!» - терм хаскеля, этот терм никаких эффектво не совершает, он возвращает некоторый терм ИО (и кладет его в main). А что и как делает этот терм IO - уже совершенно другой вопрос, не имеющий отношения к хаскелю. Еще раз, это то же самое, если бы ф-я (displayln x) вместо того чтобы вывести х на экран, возвращала бы код на питоне, который выводил бы х на экран.

В лисп аналогично. #'(disaplyln 10) — это вычисление

Именно! Так вот штука в том, что ф-и на лиспе не возвращают вычисление, а совершают сайд-эффекты. displayln выводит аргумент на печать и возвращает void. А putStr x возвращает #`(dispalyln #,x). Которое потом (может быть когда-нибудь) будет отдано на евал.

В лисп каждая топ-левел форма выполняется через eval. В Haskell топ-левел форма в таком смысле одна и у неё есть имя main.

Ага, так вот, программа на хаскеле формирует эту форму, но не исполняет ее. То есть main = #'(blah-blah), #'(blah-blah) - результат работы программы на хаскеле, то, что программа на хаскеле вернула. И уже потом мы ее отдаем на евал ИО, но это не имеет отношения к хаскелю, т.к. язык ИО - это другой язык (вообще говоря неспецифицированный, это может быть лисп, питон, сишка - что угодно). Программа на хаскеле генерирует ИО-терм. Все, больше она не делает ничего.

То есть программа на хаскеле делает то же самое, что макросы в лиспе - генерируют код. Только в лиспе макросы написанные на лиспе генерируют код на лиспе, а в хаскеле макросы, написанные на хаскеле генерируют код не-пойми-на-чем.

А для «ф-ей g, которая возвращает код, который выведет строку при своем запуске» есть Template Haskell.

Нет, template haskell - это ф-и, которые генериуют код, который генерирует код :)

То есть чтоб понятно было:

> (define (haskell-putStr x) 
    #`(displayln #,x))
> (define (lisp-putStr x) 
    (displayln x))
> (haskell-putStr "yoba")
.#<syntax:4:6 (displayln "yoba")>
> (lisp-putStr "yoba")
yoba
> 
Так вот, все ф-и в хаскеле работают как haskell-putStr. Функций вроде lisp-putStr там нет и написать их невозможно.

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

На самом деле правильно звучала бы фраза, что монады детерминируют последовательность эффектов, надеюсь это у вас хватит ума не оспаривать?

Можно привести пример, где монады детерменируют последовательность эффектов?

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

Это конкретно в IO монаде бинд так написан что создает последовательность эффектов. Я захочу и напишу другой бинд, который не будет ничего создавать.

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

На самом деле правильно звучала бы фраза, что монады детерминируют последовательность эффектов

А, то есть про WHNF мы уже не говорим? Тогда смотрим мой пример со State c первой страницы.

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

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

У тебя проблемы с логикой. Есть твое утверждение: «любая монада создает последовательность эффектов». Если приведена монада, которая последовательности эффектов не создает, то либо это не монада, либо твое утверждение неверно. Других вариантов тут нет, обычная логика.

Быть может, ты имел ввиду НЕ ЛЮБЫЕ монады, тогда уточни, какие именно.

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

Да, я существенно изменил то утверждение, которое я защищаю.

Prelude Control.Monad.State> runState (undefined >>= \_ -> return 1) 4
(1,*** Exception: Prelude.undefined

runState, т.к. нужно проверить наличие эффектов.

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

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

Что означает эта фраза?

Мы использовали интерфейс монады. Мы использовали конкретную реализацию этого интерфейса.

Maybe это тип данных, это не монада

Монада - это тип Maybe вместе с instance Monad Maybe.

Говорить то, что maybe это монада, ты можешь говорить тогда и только тогда ты используешь операцию относительно которой он является монадой, т.е. когда ты используешь bind.

Во-первых, Maybe - это монада вне зависимости от меня лично.

Во-вторых, в class Monad четыре функции. Любая из них может быть использована, и этого достаточно.

я думаю тебе будет не сложно привести хотя бы один контрпример, в котором порядок эффектов не определен

Так вроде, уже привели.

ST

Да, точно, про ST забыл.

Cont, Maybe, State, STM, Either, LogicT,

И?

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

любой bind в Maybe

Конкретнее можно? То есть пример кода, и указать где там что детерменируется.

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

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

Если приведена монада, которая последовательности эффектов не создает,

В этом треде не было приведено примера монады имеющей эффекты, но не создающих их последовательность.

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