Здравствуйте, 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.