Как стать автором
Обновить

Комментарии 8

Заранее прошу прощения за длинный комментарий.

Признаться честно, мне было сложно проследить нить рассуждений автора. Сложно было отделить… скажем так API от тонкостей реализации в тексте. То есть сложно было вычленить ту часть кода, которая мне нужна, чтобы вот взять и начать использовать эту монаду на практике.

Позволю себе несколько ремарок:
1) Статус определённой вначале функции test (я бы назвал ее лучше example) для меня был темным до тех пор, пока я не увидел листинг диалога с интерпретатором в конце статьи. Итак:
Функция тест является описанием протокола взаимодействия с неким собеседником. Замечу, что нам не интересно кто это будет и какого будет его состояние, мы просто описываем последовательность отправок и приёма сообщений (а также, возможно, некоторого промежуточного ввода\вывода, допустим обращения к базе, что реализуется через вызов функции io). Именно такое описание взаимодействий есть цель, к которой стремится автор в течение всей статьи.

2) «Дабы не отвлекаться на лишние детали и не иметь необходимости запускать несколько программ, я упрощу задачу для статьи». На мой взгляд всё лишь усложнилось, потому что перестало быть видно «отдельных участников» обмена сообщениями. Лично для меня это было понять тяжелее всего. Но пока по отложим этот вопрос.

3) Итак, функции send и response. Когда я впервые увидел эти функции при первом беглом чтении статьи, я решил, что это и есть ОНО — отделение посылки сообщения и ответа на него, ан нет. На самом деле функцию send стоило бы назвать sendAndRecieve, ибо она описывает не только ЧТО отправить, но и КАК обработать полученный в ответ результат. А функцию response (ответ) в свою очередь лично я бы назвал request (запрос), ибо это более точно отражает, на мой взгляд, суть процесса.

4) Наконец, run — это инициация диалога act (да, того самого, который представлен, например, функцией test) с собеседником, заданным состоянием a.

5) И последнее — в данном примере мы ведём диалог сами с собой (trace и listener помогают нам в этом)! Может быть это тривиальная мысль, но я никак не мог ее уловить, смотрим: сперва мы инициализируем два диалога с самим собой, причем наш ввод выступает как раз тем самым «собеседником», с которым мы общаемся посредством протокола test. В первый раз нам прислали 10, во второй — 20. По каким-то одним нам ведомым причинам в ответ мы отправляем, соответсвенно, 11 и 21 (это и будут первые слагаемые нашей результирующей суммы). Они возводятся в квадрат нашим протоколом и вновь обратно к нам. Теперь мы добавляем более безумные 444 и 122, в результате дающие нам суммы 465 и 133.

Вывод: я заключил для себя следующее. Функции, описывающие протокол (типа test) взаимодействия, я бы назвал «серверной частью» (для простоты восприятия). Конкретный же «клиент» отправляет «запросы» к этому протоколу откуда-то извне (легко переписать это дело на сокеты) — в нашем случае это была строка интерпретатора и функция f (которую опять же следовало бы назвать как-то более осмысленно).
Уф, прошу прощения еще раз, поправлю сам себя:

4) Конечно же, а — это не состояние собеседника, а скорее состояние «сервера» перед диалогом по «протоколу» act.
Спасибо большое за обширный ответ, попробую внести правки, чтобы всё это было проще понять. Без свежего взгляда сложно понять, что именно может вызвать трудности в понимании.
на C# исходная задача реализуется примерно так:

private static IObservable Test(int v)
{
var sum =
from x in SendRequest(v)
from y in SendRequest(x*x)
select x + y;
return sum.Select(x =>
{
Console.WriteLine(x);
return new Unit(); // это нужно потому что void - это не тип.
});
}
Разве это готовый код, который можно скомпилировать и запустить, и в котором можно «пообщаться с собой»? Где реализация SendRequest? Что такое Unit? При этом Вы пишете в консоль прямо в коде, описывающем протокол взаимодействия.
Увы, но на мой взгляд это демонстрация минусов императивных языков, Вы не моргнув и глазом намешали описание взаимодействия и тонкости конкретной реализации.
Прошу прощения, я был не прав, Вы привели верный аналог функции test от автора.
Всё потому, что LINQ — монада :)
Кстати, если немного усложнить пример:
test2 = do
    x <- response "hello"
    io $ putStrLn x
    y <- response x
    z <- response (++ show (:: Int))
    io $ putStrLn $ "select from DB: " ++ show y ++ show (:: Int)
    t <- io $ selectSmthFromDB y z
    io $ writeFile "tmp" t
примерно так же…
var test2 =
                from x in SendRequest("hello")
                let _ = WriteLine(x)
                from y in SendRequest(x)
                from z in SendRequest(x + y)
                let __ = WriteLine("select from DB: " + y + z)
                let t = selectSmthFromDB(y, z)
                select WriteFile("tmp", t);

предполагается, что WriteLine/WriteFile возвращают какое нить значение, например Unit
Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации

Изменить настройки темы

Истории