Кто-нибудь когда-нибудь сталкивался с трансформатором монады в дикой природе?


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

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

поэтому мне интересно: являются ли Monad transformers лучшей практикой при решении этих общих задач, упомянутых выше?

6 51

6 ответов:

сообщество Haskell разделено по этому вопросу.

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

  • разработчики GHC обычно избегают трансформаторов монад, предпочитая сворачивать свои собственные монады, которые интегрируют все необходимые им функции. (Мне сказали только сегодня в недвусмысленных выражениях, что GHC будет не используйте трансформатор монады, который я определил три дня назад.)

для меня трансформаторы монад очень похожи на точечное Программирование (т. е. Программирование без именованных переменных), что имеет смысл; в конце концов, они точно программируют без точек на уровне типа. Я никогда не любил точечное программирование, потому что полезно иметь возможность вводить случайное имя.

Что я наблюдаю на практике это

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

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

  • где блеск трансформаторов монады в модульности и повторном использовании. Это свойство прекрасно продемонстрировано Ляном, Худаком и Джонсом в их эпохальной статье "трансформаторы монады и модульные интерпретаторы".

являются ли Monad transformers лучшей практикой при решении этих общих задач, упомянутых выше?

Я бы сказал нет. где монады трансформаторов are лучшая практика, где у вас есть линейка продуктов связанных абстракций, которые вы можете создавать, составляя и повторно используя трансформаторы монады по-разному. В таком случае вы, вероятно, разрабатываете ряд трансформаторов монады, которые важны для вашей проблемной области (например, тот, который был отклонен для GHC), и вы (а) составляете их несколькими способами; (б) достигаете значительного количества повторного использования для большинства трансформаторов; (в) инкапсулируете что-то нетривиальное в каждом трансформаторе монады.

мой трансформатор монады, который был отклонен для GHC, не встретил ни одного из критерии а)/b) / С) выше.

концепция трансформаторов монад это довольно сложно и трудно поймите, трансформаторы монады ведут к очень сложный тип сигнатур

Я думаю, что это немного преувеличение:

  • использовать определенный стек монад трансформатора не сложнее, чем обычную монаду. Просто подумайте о слоях\стеках, и все будет в порядке. Вам почти всегда никогда не нужно поднимать чистую функцию (или конкретное действие ввода-вывода) больше, чем однажды.
  • как уже упоминалось, скройте свой стек Monad в newtype, используйте generalized derive и скройте конструктор данных в модуле.
  • старайтесь не использовать конкретный стек монады в сигнатуре типа функции, напишите общий код с классами типа монады, такими как MonadIO, MonadReader и MonadState (используйте расширение гибких контекстов, которое стандартизировано в Haskell 2010).
  • используйте библиотеки, такие как fclabels, чтобы уменьшить шаблонные действия, которые обращаются к частям записи в a Монада.

трансформаторы монады-это не только ваши варианты, вы можете написать пользовательскую монаду, использовать монаду продолжения. У вас есть изменяемые ссылки/массивы в ИО (глобальные), СТ (местные и контролируемые, никаких ИО действия), МВАР (синхронизации), тварь (транзакций).

Я слышал, что потенциальные проблемы эффективности с трансформаторами Monad могут быть смягчены просто путем добавления встроенных прагм для привязки/возврата в источнике библиотеки mtl/transformers.

Я недавно "упал" на композицию монады в контексте F#. Я написал DSL с сильной опорой на монаду состояния: все компоненты полагаются на монаду состояния: парсер (parser monad на основе монады состояния), таблицы соответствия переменных (более одного для внутренних типов), таблицы поиска идентификаторов. И поскольку все эти компоненты работают вместе, они полагаются на одну и ту же монаду состояния. Поэтому существует понятие государственного состава, которое объединяет различные локальные государства, и понятие методы доступа к состояниям, которые предоставляют каждому algo собственную видимость состояния.

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

поэтому, чтобы ответить на вопрос: да, Трансформеры монады существуют в "дикой природе". Тем не менее, я бы решительно возражал против их использования "из коробки". Напишите свое приложение с помощью простых строительных блоков, используя небольшие мосты ручной работы между вашими модулями, если вы в конечном итоге используете что-то вроде трансформатора монады, это здорово; не начинайте оттуда.

а насчет типа подписи: я пришел чтобы думать об этом типе программирования как о чем-то очень похожем на игру в шахматы с завязанными глазами (и я не шахматист): ваш уровень мастерства должен быть таким, чтобы вы "видели" свои функции и типы, соответствующие друг другу. Сигнатуры типов в основном являются отвлечением, если вы явно не хотите добавлять ограничения типа по соображениям безопасности (или потому, что компилятор заставляет вас давать их, например, с записями F#).

Я думаю, что это заблуждение, только монада ИО не чиста. монады как Напишите/Т/читатель/Т/государство / т / ст монады чисто функциональный еще.

Мне кажется, что существует более одного понятия о термине pure / non-pure. Ваше определение "IO = unpure, everything else = pure" звучит похоже на то, о чем говорит Пейтон-Джонс в "Укрощении эффектов" (http://ulf.wiger.net/weblog/2008/02/29/peyton-jones-taming-effects-the-next-big-challenge/). On с другой стороны, реальный мир Haskell (на последних страницах главы Monad Transformer) противопоставляет чистые функции монадической функции в целом - утверждая, что вам нужны разные библиотеки для обоих миров. Кстати, можно утверждать, что IO также чист, это побочные эффекты, инкапсулированные в функцию состояния с типом RealWorld - > (a, RealWorld). В конце концов, Haskell называет себя чисто функциональным языком (IO включен, я полагаю :-).)

мой вопрос не так многое о том, что можно сделать теоретически, но больше о том, что было доказано полезным с точки зрения разработки программного обеспечения. Трансформаторы монад допускают модульность эффектов (и абстракций в целом), но разве что направление программирования должны направляетесь?

когда я изучал монады, я построил приложение, используя стек StateT ContT IO для создания библиотеки моделирования дискретных событий; продолжения использовались для хранения монадических потоков, при этом StateT удерживал очередь запускаемых потоков и другие очереди, используемые для приостановленных потоков, ожидающих различных событий. Это сработало довольно хорошо. Я не мог понять, как написать экземпляр Monad для оболочки newtype, поэтому я просто сделал его синонимом типа, и это сработало довольно что ж.

в эти дни я, вероятно, свернул бы свою собственную монаду с нуля. Однако всякий раз, когда я это делаю, я смотрю на "все о монадах" и источник MTL, чтобы напомнить мне, как выглядят операции привязки, поэтому в некотором смысле я все еще думаю в терминах стека MTL, хотя результат-это пользовательская монада.

Так что то, что имеет тенденцию быть скорее глобальный, как журнал или конфигурация, вы бы предложили поставить в IO монада? От взгляда (по общему признанию очень ограниченный набор) примеров, я прихожу думать, что код Хаскелла имеет тенденцию быть либо чистый (т. е. совсем не монадический) или в монаде ИО. Или это заблуждение?

Я думаю, что это заблуждение, только монада IO не чиста. монады как написать/Т/читатель/Т/Государственной/т/ст монады являются чисто функциональный все еще. Вы можете написать чистую функцию, которая использует любую из этих монад внутренне, как этот совершенно бесполезный пример:

foo :: Int -> Int
foo seed = flip execState seed $ do
    modify $ (+) 3
    modify $ (+) 4
    modify $ (-) 2

все это делает потоковое / водопроводное состояние неявно, то, что вы бы сделали сами вручную явно, нотация здесь просто дает вам хороший синтаксический сахар, чтобы он выглядел императивно. Здесь вы не можете выполнять какие-либо действия ввода-вывода, вы не можете вызывать какие-либо внешние функции. ST monad позволяет вам иметь реальные изменяемые ссылки в локальной области, в то время как имея чистый функциональный интерфейс, и вы не можете делать никаких действий ввода-вывода там, это все еще чисто функционально.

вы не можете избежать некоторых действий IO, но вы не хотите возвращаться к IO для всего, потому что там все может пойти, ракеты могут быть запущены, у вас нет контроля. Haskell имеет абстракции для управления эффектными вычислениями при различной степени безопасности / чистоты, IO monad должен быть последним средством (но вы не можете полностью избежать этого).

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

видели глава Реальный Мир Хаскелл который использует трансформаторы монады?