Здравствуйте, BulatZiganshin, Вы писали:
BZ> сейчас, я например вижу, что многие люди, не знакомые с хаскелом, считают, что монады — это только способ имитации императивности. а ведь на самом деле это ещё 30-40 кг легкоусвояемого вкуснячика!
Так-с... А здесь попрошу поподробнее.. Я думаю такая тема будет интересна многим.
BZ>> сейчас, я например вижу, что многие люди, не знакомые с хаскелом, считают, что монады — это только способ имитации императивности. а ведь на самом деле это ещё 30-40 кг легкоусвояемого вкуснячика!
M>Так-с... А здесь попрошу поподробнее.. Я думаю такая тема будет интересна многим.
если ты серьёзно, то самый простой способ — посмотреть спсиок писем, которые я написал (или даже только тех, за которые меня наградили)
Здравствуйте, BulatZiganshin, Вы писали:
BZ>если ты серьёзно, то самый простой способ — посмотреть спсиок писем, которые я написал (или даже только тех, за которые меня наградили)
На самом деле внимательно слежу за твоими постами
Наверное нужно точнее сформулировать вопрос..
Что такое Хаскелевые монады я в принципе представляю. Даже пытался изобразить нечто похожее на C# здесь
Но общее впечатление пока от них — исключительно имеративные возможности в Хаскеле + некий паттерн чтоли. Ну вот не удалось мне увидеть пока чего-то большего.
Поясню как я их вижу.
Монада — это класс реализующий интерфейс IMonad, с >>=, return и т.д. а также удовлетворяющий монадическим законам. С этим понятно.
Есть монада State. С ней тоже вроде все понятно состояние и состояние. Его можно передавать по цепочке в неизменном виде, а можно и изменить.
Как только у нас появилась монада State мы можем делать IO. IO тот же State, только в состоянии хранится вся информация необходимая для ввода-вывода. Хендлы открытых файлов, этц. Естественно все это спрятано внутри монады и снаружи все выглядит как обычный интерфейс IMonad(в ООП-шном смысле).
С List-ом тоже вроде понятно. Это реализация интерфейса IMonad только List-специфичная. Вот чего не могу понять что в этом особенного?
Ну есть допустим в .NET интерфейс IEnumerable, который позволяет представлять все что угодно в Enumer-абельном виде. Ну здорово кто же спорит. Но ведь подобных интерфейсов вагон и маленькая тележка....
Я к чему вообще. Скорее всего в моем понимании монад есть какой-то недостаток. То есть я вижу в монаде исключительно IMonad и не более того. Не вижу 40 кг легоусваяемости
Поэтому и хочется чтобы меня ткнули куда-то носом или долбанули палкой по башке в лучших традициях дзен буддизма чтобы снизошло на меня просветление
З.Ы. А "All about monads" на которую ты давал ссылку тута
Mirrorer,
BZ>> сейчас, я например вижу, что многие люди, не знакомые с хаскелом, считают, что монады — это только способ имитации императивности. а ведь на самом деле это ещё 30-40 кг легкоусвояемого вкуснячика!
M>Так-с... А здесь попрошу поподробнее.. Я думаю такая тема будет интересна многим.
Вот-с кратенький такой список:
Продолжения
Обработка исключений
ГУИ
Логгинг
Коммуникации между процессами
Парсеры
Интерпретаторы
Энергичное исполнение кода
Интерфейс к коду на других языках (FFI)
Здравствуйте, Last Cjow Rhrr, Вы писали:
LCR>Вот-с кратенький такой список:
(Список нагло изничтожен)
Не, доктор, я то все понимаю. Но все прелести в списке можно вполне реализовать без монад.
Вот где бы посмотреть статьи по типу "Вот стандартный подход решения задачи, и при нем мы поимели гемморой размером с кулак, а вот мы привлекли монады, и волосы у нас стали мягкими и шелковистыми.."
Можно конечно смотреть сырцы всяких там Parsec-ов, но это долго и непродуктивно Допустим плюсы ООП-шных паттернов мне видны без увеличительного стекла. А вот с монадами что-то не складывается Хочется верить что это временно
Здравствуйте, Mirrorer, Вы писали:
M>Я к чему вообще. Скорее всего в моем понимании монад есть какой-то недостаток. То есть я вижу в монаде исключительно IMonad и не более того. Не вижу 40 кг легоусваяемости :(
Да всё у тебя верно с пониманием. Неверно понимать монады исключительно как императив.
Монада — это IMonad, которую может реализовать не только поледовательное вычисление, но и вычисление с возможным результатом, вычисление с несколькими результатами, бэктрекинг, STM, даже вот Logic монада есть и целая толпа других вычислений.
Здравствуйте, Last Cjow Rhrr, Вы писали:
LCR>Продолжения LCR>Обработка исключений LCR>ГУИ LCR>Логгинг LCR>Коммуникации между процессами LCR>Парсеры LCR>Интерпретаторы LCR>Энергичное исполнение кода LCR>Интерфейс к коду на других языках (FFI)
Бэктрекинг
Логика
STM
Multiresult
optional result
случайные значения
недетерминированность
да и самому можно толпу придумать — например, упорядочивание результатов, или для моделирования устройств — вычисления с тактами, ну и т.д.
Здравствуйте, Mirrorer, Вы писали:
M>Не, доктор, я то все понимаю. Но все прелести в списке можно вполне реализовать без монад.
Да можно, конечно. Прелести обычные, те, что мы видим у использования общего интерфейса — возможность работать с вычислением, не задумываясь что это за вычисление, возможность объединять эти вычисления общим способом и т.д.
LCR>>Вот-с кратенький такой список: M>(Список нагло изничтожен)
M>Не, доктор, я то все понимаю. Но все прелести в списке можно вполне реализовать без монад. M>Вот где бы посмотреть статьи по типу "Вот стандартный подход решения задачи, и при нем мы поимели гемморой размером с кулак, а вот мы привлекли монады, и волосы у нас стали мягкими и шелковистыми.."
M>Можно конечно смотреть сырцы всяких там Parsec-ов, но это долго и непродуктивно
если посмотреть на императивный яхык и взять в нём конструкцию типа
do { x<-a; y<-b; c }
то какой смысл здесь можно придать точке с запятой? это конструкция последовательного выполнения, и она всегда таковой остаётся, без вариантов. а что если эту ';' сделать интерфейсом, и позволить писать всякие её реализации, которые можно успешно использовать с всё тем же кодом?
монады это и есть обощённый интерфейс, позволяющий придавать этой точке с запятой самые рахличные смыслы (ну ты наврно в курсе, что в хаскел вышеупомянутое транслируется в
a >>= (\x -> b >>= (\y -> c ))
и разный смысл предаётся этому '>>=')
parsec как раз вполне подходящий пример, и ты в курсе наверно, что когда в boost включили аналогичную библиотеку, то им пришлдось сэмулировать и lazy evaluation, и как я понимаю parsing monad, чтобы добиться тех же возможностей с бэктрекингом. заметь, что подобных бибилиотек, позволяющих описывать парсер средствами обычного языка, а не использовать кодогенератор типа yacc, в других языках просто нет
другой классический пример — поиск значений в базе. без монад его можно записать как:
find x y = case (lookup base x) of
Nothing -> Nothing
Just a -> case (lookup base y) of
Nothing -> Nothing
Just b -> Just (a+b)
с монадой же он выглядит как:
find x y = do a <- lookup base x
b <- lookup base y
return (a+b)
при этом монада Maybe вступает в дело автоматически и обеспечивает, что при возвращении Nothing любым поиском дальнейшие вычисления скипаются и возвращается Nothing как общий результат. собюственно, вышенаписанный код и описывает как будет выглядеть ниженаписанный после рассахаривания. понятно, что при этом испольуется другая реализация всё той же >>=, реализация из instance Monad Maybe
если же lookup будет возвращать список найденных элементов, то этот код волшебным образом начнёт возвращать список их сумм и это уже будет эквивалентно list comprehension:
find x y = [ a+b | a <- lookup base x, b <- lookup base y ]
собтвенно, в хаскел одно время можно было записывать в синтаксисе list comprehension вычисления в любых монадах, потом это убрали, чтоб не путать новичков сложными error messages
Mirrorer,
M>Не, доктор, я то все понимаю. Но все прелести в списке можно вполне реализовать без монад. Вот где бы посмотреть статьи по типу "Вот стандартный подход решения задачи, и при нем мы поимели гемморой размером с кулак, а вот мы привлекли монады, и волосы у нас стали мягкими и шелковистыми.."
Пока я только-только продравшись сквозь YAHT чувствую на уровне мозжечка, что монады — любопытная штука, позволяющая внешним по отношению к коду образом вносить структуру в программу и влиять на поведение. Но чтобы поговорить более предметно, мне нужно поковыряться с ними побольше. Так что не сейчас.
Здравствуйте, Last Cjow Rhrr, Вы писали:
LCR>Пока я только-только продравшись сквозь YAHT чувствую на уровне мозжечка, что монады — любопытная штука, позволяющая внешним по отношению к коду образом вносить структуру в программу и влиять на поведение. Но чтобы поговорить более предметно, мне нужно поковыряться с ними побольше. Так что не сейчас. :-)
Значит тебя ещё ждут приключения с комонадами и стрелками :-)
LCR>Пока я только-только продравшись сквозь YAHT чувствую на уровне мозжечка, что монады — любопытная штука, позволяющая внешним по отношению к коду образом вносить структуру в программу и влиять на поведение. Но чтобы поговорить более предметно, мне нужно поковыряться с ними побольше. Так что не сейчас.
продравшись? а ведь yaht считается самым порстым и доходчивым мануалом
проблема в том, что трудно понять, что читать дальше; нет какого-то чёткого мануала следующего уровня. во всяком случае, не монады — имхо это не настолько важная и интересная вещь
если вас интересует практическое, "системное" прогшраммирование — то однозначно "awkward squad"
свои "IO Inside" и "OOP мы type calsses" я наверно уже перерекламировал но по крайней мере в первом приводятся примеры того, как использовать фукнциоланльный подход и к императивному программированию. а второе необходимо порчесть когда вы всерьёз заинтересуетесь type классами — они только с виду похожи на C++-ные
Здравствуйте, BulatZiganshin, Вы писали:
BZ>продравшись? а ведь yaht считается самым порстым и доходчивым мануалом
Начало у него действительно отличное. Но допустим раздел Continuation Passing Style я так и не понял. Сумбурно как-то. И монады тоже не идеально описаны ИМХО. All about monads в этом плане гораздо лучше..
Mirrorer wrote: >
> Можно конечно смотреть сырцы всяких там Parsec-ов, но это долго и > непродуктивно Допустим плюсы ООП-шных паттернов мне видны без > увеличительного стекла. А вот с монадами что-то не складывается Хочется > верить что это временно
Ну, попробую я. Надо, в конце концов, закрепить за собой статус haskell
newbie .
Попробуй посмотреть на оператор bind как обобщение композиции. При
композиции функций мы получаем новую функцию (f.g). Для вычисления
значения (f.g) x результат вычисления (g x) передается функции f. Все
элементарно.
Отличие монадных действий от функций:
1) помимо аргументов, они неявно получают некое состояние
2) могут генерировать меньше/больше одного результата
3) могут оказывать эффект на состояние
Чтобы обобщить композицию функций до композиции действий, нужно
1) протаскивать состояние
2) для выражения 'g >>= f' f может выполняться столько раз, сколько
результатов было получено в результате вычисления g.
Здесь нужно заметить, что состояние не является глобальным, количество
копий этого состояния и доступ к нему очень легко контролировать; его
можно локально модифицировать и производить откаты.
Вот и все. Если функцию (f.g.h.u) можно рассматривать как конвейер, в
котором каждый из элементов конвейера получает результаты обработки на
предыдущем шаге, то действие (u >>= h >>= g >>= f) в общем случае
является деревом конвейеров, с потенциально тупиковыми ветками, причем в
каждой ветке место одной ленты конвейера у нас есть 2 параллельные
ленты: по одной ленте передаются аргументы/результаты вычислений, как и
в случае функций, по второй передается неявное состояние.
Что мы получаем от такой абстрактной конструкции? Повторюсь, это важно:
возможность композиции. Возможность получить из элементарных шагов
вычисления более крупные вычисления, определив в единственном месте
программы, как эта композиция должна работать.
Простой пример. Представим, что у нас есть процедуры foo, bar, baz,
которые для вычисления результата должны иметь доступ к некоторому
контексту ctx. Что мы делаем в ОО-программе? Если foo, bar, baz — методы
одного класса Blabla, и разделение контекста нам нужно только в пределах
одного объекта, все просто — мы добавляем приватное поле ctx в класс
Blabla. Если классов или объектов много, начинаются сложности — явная
передача параметра ctx в конструкторы или методы, синглтоны,
ServiceProvider'ы и т.д.
А вот как проблема решается при помощи монады Reader:
import Control.Monad
import Control.Monad.Reader
import Text.Printf
foo :: Int -> Reader String String
foo x = do
ctx <- ask
return $ printf "foo %d called with ctx=%s" x ctx
bar :: Int -> Reader String String
bar x = do
ctx <- ask
return $ printf "bar %d called with ctx=%s" x ctx
baz :: Int -> Reader String String
baz x = do
ctx <- ask
return $ printf "bar %d called with ctx=%s" x ctx
combineOutputs actions = do
results <- sequence actions
return $ unlines results
run ctx actions = do
putStrLn $ (runReader (combineOutputs actions) ctx)
putStrLn "======================================"
main = do
run "context1" [foo 1, bar 1]
run "context2" [baz 2, foo 2, foo 1, bar 5]
run "context3" [bar 7]
Вывод:
foo 1 called with ctx=context1
bar 1 called with ctx=context1
======================================
bar 2 called with ctx=context2
foo 2 called with ctx=context2
foo 1 called with ctx=context2
bar 5 called with ctx=context2
======================================
bar 7 called with ctx=context3
======================================
Для разделения контекста между действиями a и b достаточно объединить их
в один do-блок: runReader (do { a; b }) ctx, причем a и b могут
находиться на различной глубине стека вызовов.
BZ>>продравшись? а ведь yaht считается самым порстым и доходчивым мануалом
M>Начало у него действительно отличное. Но допустим раздел Continuation Passing Style я так и не понял. Сумбурно как-то. И монады тоже не идеально описаны ИМХО. All about monads в этом плане гораздо лучше..
cps, монады, type classes я бы посчитал продвинутым материалом, которому там не место. но тут конечно надо знать, что там читать, а что скипать я в своё время бросил изучать хаскел из-за того, что в gentle глава о монадах была написана с особым цинизмом
>> увеличительного стекла. А вот с монадами что-то не складывается Хочется >> верить что это временно
PM>Ну, попробую я. Надо, в конце концов, закрепить за собой статус haskell PM>newbie .
отличное описание! то, что я конце концов понял, прочитав мириад разных тюториалов, вы сформулировали коротко и точно, подчеркнув самую суть
BulatZiganshin wrote: > отличное описание! то, что я конце концов понял, прочитав мириад разных > тюториалов, вы сформулировали коротко и точно, подчеркнув самую суть
Спасибо . Для меня большая честь получить такой отзыв от автора
библиотек, попавших в репозиторий darcs.haskell.org.
Здравствуйте, BulatZiganshin, Вы писали:
BZ>cps, монады, type classes я бы посчитал продвинутым материалом, которому там не место. но тут конечно надо знать, что там читать, а что скипать :)) я в своё время бросил изучать хаскел из-за того, что в gentle глава о монадах была написана с особым цинизмом :))
Чёрт, а я наоборот, по GentleIntro учился, а YAHT бросил :)
Здравствуйте, Mirrorer, Вы писали:
L>>Значит тебя ещё ждут приключения с комонадами и стрелками :-)
M>А вот такой вопросец. Комонады и стрелки изучать лучше после прокачки в ТК или и без ТК нормально пойдет?
Я ТК, к сожалению, не знаю. Поэтому сравнить не могу.
Здравствуйте, palm mute, Вы писали:
PM>Спасибо . Для меня большая честь получить такой отзыв от автора PM>библиотек, попавших в репозиторий darcs.haskell.org.
Ужас! В декларативном — тишина, а в Философии Монады обсуждають
M>>Теория Категорий. A>А эта ТК имеет отношение к Хаскелю или речь о мат. базисе для изучения?
монады — это объект из теории категорий. для того, чтобы понять *теоретичсекие* основы, которые отцы Хаскела под императвиность подвели, это нужно изучать. есть даже несколько попыток введения в ТК для программистов
я лично не читал, и не собираюсь. как и комонады — практическая польза от них? а вот стрелки используются для более удобной композиции функций, это для *практического* программирования олехно будет прочесть. опять же, ТК я думаю для этого не понадобится
Здравствуйте, BulatZiganshin, Вы писали:
BZ>монады — это объект из теории категорий. для того, чтобы понять *теоретичсекие* основы, которые отцы Хаскела под императвиность подвели, это нужно изучать. есть даже несколько попыток введения в ТК для программистов :)
Моё мнение такое — я смотрю, какие изящные решения были придуманы людьми, и понимаю, что мне пришлось бы долго думать, чтобы до такого додуматься. А люди эти вещи взяли из ТК. Это мой единственный стимул изучения ТК. Брать самому, а не смотреть на то, что дали.
BZ>я лично не читал, и не собираюсь. как и комонады — практическая польза от них? а вот стрелки используются для более удобной композиции функций, это для *практического* программирования олехно будет прочесть. опять же, ТК я думаю для этого не понадобится
Вооооот! А я как раз сейчас балуюсь с комонадами, и многие вещи, для которых используют стрелки (например, сигнальные типы из FRP), прекрасно решаются с помощью комонад. Сейчас у меня к сожалению мало времени, а так я ещё хочу побаловаться с комонадами для написания бэктрекинга. "На бумаге" получается как минимум ничуть нихуже, чем в монадах.
BZ>>монады — это объект из теории категорий. для того, чтобы понять *теоретичсекие* основы, которые отцы Хаскела под императвиность подвели, это нужно изучать. есть даже несколько попыток введения в ТК для программистов
L>Моё мнение такое — я смотрю, какие изящные решения были придуманы людьми, и понимаю, что мне пришлось бы долго думать, чтобы до такого додуматься. А люди эти вещи взяли из ТК. Это мой единственный стимул изучения ТК. Брать самому, а не смотреть на то, что дали.
может быть. мне лично кажется, что для придумывания монад лезть в математику ни к чему. многие монады — это просто невидимая передача состояния. в целом же монады — это нечто вроде "страгегии вычислений". тебе дают отдельные операции, савязанные >>=, и ты можешь определить это >>= как душе угодно. хочешь — можешь порпускать каждую вторую операцию. хочешь — повтори 10 раз и затем сделай "ку!". хочешь — запиши историю всех внутренних значений для отладки. вот и вся премудрость
BZ>>я лично не читал, и не собираюсь. как и комонады — практическая польза от них? а вот стрелки используются для более удобной композиции функций, это для *практического* программирования олехно будет прочесть. опять же, ТК я думаю для этого не понадобится
L>Вооооот! А я как раз сейчас балуюсь с комонадами, и многие вещи, для которых используют стрелки (например, сигнальные типы из FRP), прекрасно решаются с помощью комонад. Сейчас у меня к сожалению мало времени, а так я ещё хочу побаловаться с комонадами для написания бэктрекинга. "На бумаге" получается как минимум ничуть нихуже, чем в монадах.
Здравствуйте, BulatZiganshin, Вы писали:
BZ>может быть. мне лично кажется, что для придумывания монад лезть в математику ни к чему.
Это то да! Но то монады — их уже вытащили из ТК и дали нам разжёванное, а сколько там ещё непопробованного лежит? ;-)
BZ>печально сознавать, что есть люди поумнее меня :))
BZ>>может быть. мне лично кажется, что для придумывания монад лезть в математику ни к чему.
L>Это то да! Но то монады — их уже вытащили из ТК и дали нам разжёванное, а сколько там ещё непопробованного лежит?
а мне кажется, что монады просто вытащили на свет для того, чтобы дать математическое объяснение тому, как это устроен в/в в lazy языках. вот представь — идёшь ты по двору, ловишь кошку, жаришь её, а потом заглядываешь в словарь и найдя там подходящую картинку, объясняешь окружающим — я поймал кошку. а они потом всё лезут и лезут словарь, надеясь нарыть там что-нибудь съедобное
Здравствуйте, BulatZiganshin, Вы писали:
BZ>а мне кажется, что монады просто вытащили на свет для того, чтобы дать математическое объяснение тому, как это устроен в/в в lazy языках. вот представь — идёшь ты по двору, ловишь кошку, жаришь её, а потом заглядываешь в словарь и найдя там подходящую картинку, объясняешь окружающим — я поймал кошку. а они потом всё лезут и лезут словарь, надеясь нарыть там что-нибудь съедобное :))
:) Ну, я попытался объяснить свою позицию в одном из постов. Смысл такой — если я потом залез в словарь и определил кошку, формализовал охоту на неё и т.д. это одно, т.к. дальнейшие мои кошкодомогательства будут более эффективны (производительны) в силу выработанных приёмов, абстракций и т.д. Я зафиксировал паттерн. А вот если я в словарь не полезу, то я потом со второй кошкой и облажаться, т.к. не пойму, что эта животина точно такая же, как и первая. И как её ловить буду придумывать заново.
добрался наконец до ответа на это письмо
M>Монада — это класс реализующий интерфейс IMonad, с >>=, return и т.д. а также удовлетворяющий монадическим законам. С этим понятно.
M>Есть монада State. С ней тоже вроде все понятно состояние и состояние. Его можно передавать по цепочке в неизменном виде, а можно и изменить.
это верно
M>Как только у нас появилась монада State мы можем делать IO. IO тот же State, только в состоянии хранится вся информация необходимая для ввода-вывода. Хендлы открытых файлов, этц. Естественно все это спрятано внутри монады и снаружи все выглядит как обычный интерфейс IMonad(в ООП-шном смысле).
упаси боже. IO и ST — это всего лишь способы упорядочить операции. они нужны потому, что при взаимосдействии с внешним миром нужно вполнять операции строго в заданном порядке, хотя между ними незаметно никакой связи по данным. ну какая например разница, сначала ClrScr сделать, а потом строку вывести, или наоборот?
эти монады через свой фиктивный аргумент RealWorld, который аналогичнсо state путешествует от операции к операции, гаранируют, что операции будут выполнены строго в заданном порядке. в конечном счёте всё упирается в вызовы Сишных функций, которые имеют тип "... -> IO a", т.е. после раскрытия этого type synonym IO, они получают и возвращают некий объект типа RealWorld. а поскольку внутрь этих сишных прцедур не заглянешь, то компилятору остаётся только согласиться с тем, что их действительно надо вызывать в том самом порядке, что описан, поскольку фиг его знает, как там эта процедура "вычисляет" сой выходной RealWorld на основани входных аргументов. вот такой вот обман компилятора
и вся программа таким образом просто-напросто описывает последовательность вызовов этих внешних Сишных процедур и передаваемые им параметры — и ничего больше! с другой стороны, это логично — ведь такие вызовы и есть единственный способ как-то повлиять на внешний мир, верно?
опять-таки, подробней смотрите в моём "IO Inside". ST — это тот же IO, только позволяющий работать лишь с переменными и массивами, специально переименованными, чтобы операции из ST нельзя было использовать в IO и наоборот. это, и плюс ещё трюк с forall типами, гарантирует что переменные/массивы, созданные внутри одного ST блока, не могут быть использованы в другом, и таким образом произведённые в нём вычисления являются чистыми, зависящими только от входных данных. я уже приводил этот пример:
f x = runST (do a <- newSTRef x
modifySTRef a (*2)
readSTRef a)
это вычисление, хоть и описано в императивном стиле, тем не менее не зависит от каких-либо обстоятельств выполнения, и всегда возвращает x*2. можно сравнить это с Сишной функцией, которой разрешено пользоваться только локальными переменными — тогда она тоже будет referential transparent, поскольку ей просто негде сохранять состояние в промежутке между вызовами
ещё одно важное отличие монады State от IO — вычисления, описанные в первой, вовсе не обязательно выполнять последовательно. это описание просто задаёт связи между данными. т.е. если State изменили в calc2 и затем использовали в calc3, то используемое в ней значение будет именно то, которое было присвоено в calc2. однако это просто связка по данным, и порядок вычислений она совсем не обязана гаранитировать. и на самом деле может быть сначала выичслено значение их calc3, а затем из calc1. ну например если в моём примере написсать "return (b++a)" вместо "return (a++b)"
монады могут быть реализоаны как ленивые и строгие. строгие выполняют операции в том порядлке, как это записано в монаде, ленивые — втом, в каком это нужно для получения ответа. технически это делается форсированием операций для строгих монад так что результат выполнения очередной операции оказывается якобы зависящим от выполнения предыдущей (используется операция seq). монада IO, понятное дело, всегда только строгая, а остальные можно реализовать и так, и эдак. скажем, здесь:
f x = runST (do a <- newSTRef x
modifySTRef a (*2)
b <- newSTRef x
readSTRef a)
в случае строгой монады всё будет выполнено последовательно (в тот момент, когда будет затребован результат "f x"), а в случае ленивой — запрос на результат приведёт к вполнению readIORef, результат которого, как выяснится, зависит от modifySTRef, а её резщультат — от первого newSTRef. второй же newSTRef так и не будет исполнен, поскольку его в цепочке зависимостей нет
впрочем, на практике, ленивые монады, как и вообще всё ленивое — это чаще всего медлительность и жуткий расход памяти (представьте себе набор зависимостей, воозникающий при записи, скажем, алгоритма умножения матриц )
M>С List-ом тоже вроде понятно. Это реализация интерфейса IMonad только List-специфичная. Вот чего не могу понять что в этом особенного?
M>Ну есть допустим в .NET интерфейс IEnumerable, который позволяет представлять все что угодно в Enumer-абельном виде. Ну здорово кто же спорит. Но ведь подобных интерфейсов вагон и маленькая тележка....
самое интересное в монадах — то, что они позволяют разделить логику работы приложения на отдлельные слои. лучше всего упоминавшуюся статью. Вадлера посмотреть, где в интерпретатор добавляют возможности, не трогая самого интерпретирующего кода
BZ>>может быть. мне лично кажется, что для придумывания монад лезть в математику ни к чему.
L>Это то да! Но то монады — их уже вытащили из ТК и дали нам разжёванное, а сколько там ещё непопробованного лежит?
в конечном счёте всё имхо определяется тем, что вы с математикой на ты, а я просто программист
palm mute,
PM>... skipped ... PM>Надеюсь, хоть чуть-чуть понятнее стало .
Спасибо, в целом хорошо. (только стиль хромает немного).
И ещё хочется какую-нибудь картинку. Какую-нибудь вот такую:
вот к этому PM> ...то действие (u >>= h >>= g >>= f) в общем случае является деревом конвейеров...
u — это начальное монадическое значение, скажем возвращённое функцией return.
Прямоугольники означают функции h, g и f :: a -> m b.
Внутри них сидит ядро, которое и выполняет полезную работу: печатает на экран, гадит в файл, достаёт пользователя и т. п.
Аргументы передаются по чёрным стрелкам;
Состояние — по пунктирным.
Каждая функция выдаёт монадическое значение (жырная синяя или фиолетовая стрелка), которая попадает в bind (жырная чёрная точка с границей соответствующего цвета-типа). Далее bind внутри себя расковыривает монадическое значение и передаёт функциям дальше.
Есть два момента:
1. bind принимает не только монадическое значение, но так же и функцию. Например, самый верхний bind должен принимать функцию h в качестве параметра. Чтобы не перегружать рисунок, придётся оговорить этот момент на словах, что я и делаю.
ps: Знаю, знаю, картинка за туториал не канает. Может быть позже выдумаю свой уникальный вариант.
Вот список прочитанных мной туториалов по монадам в хронологическом порядке
1. сообщение Редуктора.
2. глава в "истории Хаскеля" (давным давно в декларативном пролетала ссыла)
3. астронавты
3. их вторая инкарнация про ядерные отходы
4. эта (вы могли изобрести монады, но почему то не изобрели)
5. don't panic — пожалуй самая конкретная, но почти непрошибаемая. Я месяц (один месяц) буксовал на естественных трансформациях, пока не наткнулся на п. 6.
6. monadic crash course — пролил свет на многие моменты в 5. ускользнувшие почему-то.
7. YAHT
8. твои сообщения.
9. сообщение Глеба (palm_mute).
После такого списка я тоже могу сказать, "Да мужики, вы чо! Монады — это легко. Всем читать you-could-have-invented-monads!!!".
Но на самом деле you-could-have-invented-monads _недостаточно_. С одной стороны — это самый безболезненный старт, но с другой — по-прежнему непонятно, как же писать императивные программы на Хаскеле. Вот после YAHT — понятно, но не факт, что я бы врубился в него, если бы он был выше в списке.
Короче, минимального по объёму и максимального по естественности восприятия материала по-прежнему нет.
давайте не кидать всё в одну топку. там — та самая картинка, которую вы хотели. ну один к одному — как живая
LCR>Но на самом деле you-could-have-invented-monads _недостаточно_. С одной стороны — это самый безболезненный старт, но с другой — по-прежнему непонятно, как же писать императивные программы на Хаскеле. Вот после YAHT — понятно, но не факт, что я бы врубился в него, если бы он был выше в списке.
LCR>Короче, минимального по объёму и максимального по естественности восприятия материала по-прежнему нет.
это две большие разницы. то, что ты прочёл, имеет отношение именно к программированию монад вообще. тут имхо best way — "you could have invented monads" и затем "all about monads". в первой объясняется идея, во второй сказано всё о всех имеющихся монадах
императвиные программы — совершенно отдельно топик, и для этого монады понимать нифига не надо! моего http://haskell.org/haskellwiki/IO_inside имхо должно хватить с головой (если ты просёк как работает lazy evaluation), но вообще и это — оверкилл. я постараюсь как-нибудь написать введение в императивное программирование, где это жуткое понятие вообще не упоминается
Имхо, нет.
LCR>>Короче, минимального по объёму и максимального по естественности восприятия материала по-прежнему нет.
BZ>... ну а дальше надо однозначно читать ...
Блин, я забыл включить в список IO Inside .
Я подозреваю, что у других участников (lomeo, palm_mute, Mirrorer, Кодта и прочих, простите кого не включил) будут свои THE MOST RIGHT WAYS TO LEARN MONADS. Именно поэтому я не привожу здесь своё хо, в какой последовательности и что нужно читать.
Просто у меня есть идея, которой не было ни в одном из прочитанных мной туториалах. Вот эту идею я и собираюсь кристаллизовать и изложить. Только и всего.
Здравствуйте, BulatZiganshin, Вы писали:
L>>Это то да! Но то монады — их уже вытащили из ТК и дали нам разжёванное, а сколько там ещё непопробованного лежит?
BZ>в конечном счёте всё имхо определяется тем, что вы с математикой на ты, а я просто программист
обижаешь (можно на ты?)
я тоже программист. потому то через ТК пробираюсь с трудом.
Здравствуйте, Lazy Cjow Rhrr, Вы писали:
LCR>Просто у меня есть идея, которой не было ни в одном из прочитанных мной туториалах. Вот эту идею я и собираюсь кристаллизовать и изложить. Только и всего. LCR>ps: до понедельника
Ждем с нетерпением! За язык тебя никто не тянул .
Здравствуйте, Lazy Cjow Rhrr, Вы писали:
LCR>Спасибо, в целом хорошо. (только стиль хромает немного).
И тебе спасибо.
Если будет время — с удовольствием выслушаю замечания по стилю. Лучше в комментах в моем ЖЖ, здесь это будет оффтопиком.
LCR>И ещё хочется какую-нибудь картинку.
Отличная картинка и замечание по поводу разных типов у действия u и функций h, g, f. Т.к. я отвечал Mirrorer'у, расчет был на то, что читатель все это знает.
LCR>ps: Знаю, знаю, картинка за туториал не канает. Может быть позже выдумаю свой уникальный вариант.
Ждемс.
Здравствуйте, Lazy Cjow Rhrr, Вы писали:
LCR>ИМО, когда обсуждение чуть поутихнет, нужно будет отделить несколько веток и перенести в более подходящее место — в ДП. В том числе и этот топик.
Ох, почитал я остальные обсуждения. Тут вообще пол-философии пора перенести в декларативное. Всё таки полезное вполне знание обсуждается, и наверняка интересное для тех кто философию обычно не читает (я например ).
Видно надо какого-то провокатора в Декларативном завести, чтобы вопросы задавал такие, на которые все хотят знать ответ, а спросить не решаются.
Здравствуйте, Andir, Вы писали:
A>Видно надо какого-то провокатора в Декларативном завести, чтобы вопросы задавал такие, на которые все хотят знать ответ, а спросить не решаются.