Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
||
ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
[3.17.75.227] |
|
Страницы: (3) 1 [2] 3 все ( Перейти к последнему сообщению ) |
Сообщ.
#16
,
|
|
|
Небольшое уточнение: «монада как бы "заразна"» — это касается монады IO (и, вероятно, некоторых других), т.к. Монада — это класс типа, а не сам тип, она не регулирует конструирование значений типа и не запрещает наличие функций, вытаскивающих значение из монадного типа, т.е. невозможность «вытащить» значение из монады произвольным способом обеспечивается модулем, в котором тип определён. Например модуль, в котором определён тип ST, предоставляет функцию runST, вытаскивающую значение из монады ST, т.к. ST — чистый тип, без сайд-эффектов. Монаду можно определить даже для списков, чтобы воспользоваться do-нотацией:
import Control.Monad foo n = do i <- [1..n] j <- [i..n] k <- [j..n] return (i, j, k) bar n = [ (i, j, k) | i <- [1..n], j <- [i..n], k <- [j..n] ] baz n = concat $ concat $ map (\i -> map (\j -> map (\k -> (i, j, k)) [j..n]) [i..n]) [1..n] main = let n = 3 in forM_ [foo, bar, baz] $ \f -> print $ f n → [(1,1,1),(1,1,2),(1,1,3),(1,2,2),(1,2,3),(1,3,3),(2,2,2),(2,2,3),(2,3,3),(3,3,3)] [(1,1,1),(1,1,2),(1,1,3),(1,2,2),(1,2,3),(1,3,3),(2,2,2),(2,2,3),(2,3,3),(3,3,3)] [(1,1,1),(1,1,2),(1,1,3),(1,2,2),(1,2,3),(1,3,3),(2,2,2),(2,2,3),(2,3,3),(3,3,3)] — http://ideone.com/E21ZDr Как нетрудно заметить, функции foo, bar и baz абсолютно идентичны по результату и отличаются лишь во внешнем виде исходного кода. foo реализована с помощью do-нотации благодаря Monad []. https://www.fpcomplete.com/school/starting-...-the-list-monad http://en.wikibooks.org/wiki/Haskell/Under...ing_monads/List |
Сообщ.
#17
,
|
|
|
Уже развился до терминальной стадии. Но это не ослепляет меня. В D полно говна, но пока это лучшее, из того, что у меня есть.
На D потому что в данный момент это язык, которым я владею намного лучше остальных языков. Я мог бы ваять примеры на Ruby или плюсах, но это заняло бы гораздо больше времени. Цитата korvin @ Совершенно, абсолютно бесполезное занятие, особенно для объяснения, что такое монада. Автор вообще не понял, что это, смешал в кучу монаду, ST и ленивость. Зачем? Монада IO в JS, да и в (почти) любом императивном языке — это точка с запятой ( ; ), точнее это функция bind, именно она позволяет компилятору выстроить правильную последовательность действий в программе. Насчет точки с запятой - очень хорошая аналогия. помогла мне кое-что осознать. С точки зрения функционального программирования не существует алгоритма, как некоей последовательности действий. Это, ИМХО, крайне важный момент, которому, я считаю, уделяют слишком мало внимания в лекциях и учебниках. Сама природа человека строит все на цепочках событий, а тут надо забыть про это. Есть исходный материал, а есть множество функций от этого материала и множество результатов этих функций. Причем и материалы и результаты также могут быть функциямии. Все это происходит вне времени. Время конечно может участвовать как агрумент функций, но сами функции "плавают" в некоем безвременном "гиперпространстве". Суть монады, насколько я понял, как раз в формализации последовательности из двух вычислений. При этом значения аргумента и результата обернуты в монаду, а результат первого вычисления является аргументом второго вычисления. Своим "примером" монады, я скорее сымитировал один из вариантов реализации внутренностей монады, а не саму монаду. |
Сообщ.
#18
,
|
|
|
Цитата applegame @ Насчет точки с запятой - очень хорошая аналогия. помогла мне кое-что осознать. С точки зрения функционального программирования не существует алгоритма, как некоей последовательности действий. Это, ИМХО, крайне важный момент, которому, я считаю, уделяют слишком мало внимания в лекциях и учебниках. Сама природа человека строит все на цепочках событий, а тут надо забыть про это. Есть исходный материал, а есть множество функций от этого материала и множество результатов этих функций. Причем и материалы и результаты также могут быть функциямии. Все это происходит вне времени. Время конечно может участвовать как агрумент функций, но сами функции "плавают" в некоем безвременном "гиперпространстве". Суть монады, насколько я понял, как раз в формализации последовательности из двух вычислений. При этом значения аргумента и результата обернуты в монаду, а результат первого вычисления является аргументом второго вычисления. Своим "примером" монады, я скорее сымитировал один из вариантов реализации внутренностей монады, а не саму монаду. Это всё пустые философствования. Ты не можешь вернуться в прошлое, например, таким образом пространство-время — это просто поток, ленивый список моментов, вычисляющийся по мере необходимости (течении времени), преобразование одного момента в другой — чистая функция. Но что толку от всех этих аналогий? А суть монады ты неправильно понял, как и тот автор, я ж написал пример на предыдущей странице. У монады нет никаких внутренностей, это интерфейс. |
Сообщ.
#19
,
|
|
|
Цитата korvin @ Философствования - да. Пустые ли они? Не уверен. Для проектирования задачи важно понимание. Перестать мыслить в рамках последовательности действий и начать мыслить в рамках функциональных трансформаций. Фиг его знает, мне помогает.Это всё пустые философствования. Ты не можешь вернуться в прошлое, например, таким образом пространство-время — это просто поток, ленивый список моментов, вычисляющийся по мере необходимости (течении времени), преобразование одного момента в другой — чистая функция. Но что толку от всех этих аналогий? Цитата korvin @ Странно. У абстрактной монады, конечно, нет никаких внутренностей, но как же конкретные реализации вроде монады Maybe? Разве у нее нет внутренностей? Даже в твоем примере у класса IO<A> вполне есть "внутренности": join и bind. А суть монады ты неправильно понял, как и тот автор, я ж написал пример на предыдущей странице. У монады нет никаких внутренностей, это интерфейс. |
Сообщ.
#20
,
|
|
|
Цитата applegame @ Странно. У абстрактной монады, конечно, нет никаких внутренностей, но как же конкретные реализации вроде монады Maybe? Разве у нее нет внутренностей? Даже в твоем примере у класса IO<A> вполне есть "внутренности": join и bind. Странно, у интерфейса Monad, конечно, нет никаких внутренностей, но как же конкретные реализации вроде класса IO? Разве у класса нет внутренностей? Я не понимаю, в чём твоя проблема, в этом вашем D нет интерфейсов и классов? |
Сообщ.
#21
,
|
|
|
Цитата korvin @ Проблем никаких нет. Ответ ты и сам знаешь. Я не понимаю, в чём твоя проблема, в этом вашем D нет интерфейсов и классов? |
Сообщ.
#22
,
|
|
|
Попрбовал Haskell и OCaml.
Первый кошерен, второй мерзок. Кому пришла в голову бредовая идея делать отдельные математические операторы для int и float? Разделение элементов списка точками с запятой? Фу короче. А вот Хаскель - приятная штука. |
Сообщ.
#23
,
|
|
|
В хаскеле проблема ad-hoc полиморфизма просто решена здраво через type class'ы. В ocaml так просто не сделаешь, потому и отдельные операции там, где это важно с точки зрения типизации. Вместо ocaml можешь попробовать F#, это почти тот же язык, только причесанный и с многими дополнительными плюшками.
|
Сообщ.
#24
,
|
|
|
Цитата D_KEY @ Он неплох, я уже немного видел его в приведеном тобой ролике с песней о монадах. Если бы не его привязанность к .NET, может быть и поковырялся бы с ним.Вместо ocaml можешь попробовать F#, это почти тот же язык, только причесанный и с многими дополнительными плюшками. Пока поизучаю Haskell, тем более что многие вещи оказались знакомы по D (D_LANG гойловного мозга налицо). Например, бесконечные ленивые списки == бесконечные ленивые ranges. |
Сообщ.
#25
,
|
|
|
Цитата applegame @ 1) Кому пришла в голову бредовая идея делать отдельные математические операторы для int и float? 2) Разделение элементов списка точками с запятой? Фу короче. 3) А вот Хаскель - приятная штука. 1) Тому, кто придумал строгую типизацию и вывод типов. ML был придуман в 70-х, когда Хаскелла с его тайпклассами даже в проекте не было. ML полностью отрицает неявное приведение типов. 2) Вкусовщина. Мне не нравится, что имена типов пишутся со строчной буквы и странные правила использования двойной точки-с-запятой, но это такая мелочь. 3) Да, но мне интересно, что ты скажешь, когда познакомишься с ним получше и узнаешь, что, например, написав хвостово-рекурсивную функцию внезапно обнаружишь переполнение стека, из-за ленивости, и окажется, что нужно форсировать вычисления специальным образом. Или то, что ты не можешь просто взять и вставить в середину функции отладочную печать, т.к. IO заразна и тебе придётся менять тип своей чистой функции на (IO T) (а то и переписывать её полностью). Несомненно, в дефолтной всеобщей ленивости и заразном IO есть свои плюсы, но зачастую это слегка непрактично. Да и Функторы Ocaml немного удобней, понятней и проще в использовании, чем тайпклассы Хаскелла. + Если ты захочешь нормальный и удобный «динамический полиморфизм», ты скорее всего поменяешь своё мнение в пользу Ocaml. Ну или F#, да, хотя, несмотря на некоторые весьма годные улучшения по сравнению с Ocaml, вроде есть и минусы. Если не ошибаюсь, модули например в F# примитивней Ocaml'овских. Я поначалу Ocaml как-то тоже недолюбливал после Хаскелла, но потом, чем больше знакомился с ним, тем больше он мне стал нравиться (не в ущерб Хаскеллу, конечно =)). Добавлено Цитата applegame @ Например, бесконечные ленивые списки == бесконечные ленивые ranges. Гм… А как будет на D'шных рейнджах выглядеть такой код: fibs = 0 : 1 : zipWith (+) fibs (tail fibs) main = print $ take 10 fibs [0,1,1,2,3,5,8,13,21,34] В Хаскелле ленивы не только списки, он ленив весь. |
Сообщ.
#26
,
|
|
|
Цитата korvin @ Или то, что ты не можешь просто взять и вставить в середину функции отладочную печать, т.к. IO заразна и тебе придётся менять тип своей чистой функции на (IO T) (а то и переписывать её полностью). А разве там нет специального костыля с unsafePerformIO как раз для дебажного принта? Цитата korvin @ Гм… А как будет на D'шных рейнджах выглядеть такой код: Ну в расте fibs будет возвращать итератор. Подозреваю, что рейнжи в D работают точно так же. |
Сообщ.
#27
,
|
|
|
Цитата korvin @ Гм… А как будет на D'шных рейнджах выглядеть такой код: fibs = 0 : 1 : zipWith (+) fibs (tail fibs) main = print $ take 10 fibs [0,1,1,2,3,5,8,13,21,34] Аналогичный бесконечный ленивый рендж для чисел Фибоначчи можно сделать вот так: import std.range; import std.stdio; void main() { auto fibs = recurrence!((a, n) => a[n-1] + a[n-2])(0, 1); writeln(fibs.take(10)); } (a,n) => a[n-1] + a[n-2] // лямбда вычисляющая очередное число (0, 1) // первые два числа Фибоначчи Результат - http://dpaste.dzfl.pl/9850c213f69a Цитата korvin @ В Хаскелле ленивы не только списки, он ленив весь. D по умолчанию не ленив, но ленивость можно указать явно: import std.stdio; int foo() { writefln("foo"); return 5; } void bar(bool flag, lazy int data) { // аргумент data - ленивый writefln("flag = %s", flag); if(flag) writefln("data = %s", data); } void main() { bar(true, foo()); bar(false, foo()); } flag = true foo data = 5 flag = false |
Сообщ.
#28
,
|
|
|
Цитата DarkEld3r @ 1) А разве там нет специального костыля с unsafePerformIO как раз для дебажного принта? 2) Ну в расте fibs будет возвращать итератор. Подозреваю, что рейнжи в D работают точно так же. 1) Есть такое выражение: «если вы используете UnsafePreformIO, то вам не нужен Haskell» или как-то так. 2) Я жду код, а не рассуждения. Добавлено Цитата applegame @ D по умолчанию не ленив, но ленивость можно указать явно: import std.stdio; int foo() { writefln("foo"); return 5; } void bar(bool flag, lazy int data) { // аргумент data - ленивый writefln("flag = %s", flag); if(flag) writefln("data = %s", data); } void main() { bar(true, foo()); bar(false, foo()); } flag = true foo data = 5 flag = false Тут-то D и сел в лужу. Ибо сочетать ленивость и сайд-эффекты — это не в тапки гадить. http://ideone.com/A0pXvm foo = do putStrLn "foo" return 5 bar flag d = do putStrLn $ "flag = " ++ show flag x <- d if flag then putStrLn $ "data = " ++ show x else return () main = do bar True foo bar False foo → flag = True foo data = 5 flag = False foo |
Сообщ.
#29
,
|
|
|
korvin, раскрой мысль. Не очень понял, почему второй раз правильно вызывать foo. В чем фейл D?
Добавлено И вообще, если ты сделаешь x <- d внутри if'а, то будет так же, как в D |
Сообщ.
#30
,
|
|
|
Цитата korvin @ Твой код не эквивалентен моему.Тут-то D и сел в лужу. Ибо сочетать ленивость и сайд-эффекты — это не в тапки гадить. Цитата D_KEY @ Ага, korvin смухлевал. И вообще, если ты сделаешь x <- d внутри if'а, то будет так же, как в D Вот как должно было быть: http://ideone.com/GO7ZhH foo = do putStrLn "foo" return 5 bar flag d = do putStrLn $ "flag = " ++ show flag if flag then do x <- d putStrLn $ "data = " ++ show x else return () main = do bar True foo bar False foo flag = True foo data = 5 flag = False |