Подтвердить что ты не робот

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

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

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

Итак, мне интересно: лучше ли использовать трансформаторы монады, когда речь идет об этих общих задачах, упомянутых выше?

4b9b3361

Ответ 1

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

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

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

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

То, что я наблюдаю на практике, это

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

  • Монады, такие как Writer, State и Environment, настолько просты, что я не вижу большой пользы для монадных трансформаторов.

  • Где модные трансформаторы сияют в модульности и повторном использовании. Это свойство прекрасно продемонстрировано Ляном, Худаком и Джонсом в их знаменитой бумаге Monad Transformers and Modular Interpreters.

Лучше ли использовать трансформаторы монады при решении упомянутых выше общих задач?

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

Мой монадный трансформатор, который был отклонен для GHC, не соответствовал ни одному из критериев (a)/(b)/(c) выше.

Ответ 2

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

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

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

Трансформаторы Monad не являются вашими единственными опциями, вы можете написать обычную Monad, используйте Monad продолжения. У вас есть изменяемые ссылки/массивы в IO (глобальном), ST (локальные и управляемые, без операций ввода-вывода), MVar (синхронизация), TVar (транзакционный).

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

Ответ 3

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

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

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

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

Ответ 4

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

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

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

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

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

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

Вы видели главу из Real World Haskell, которая использует монадные трансформаторы?

Ответ 5

Я думаю, что это заблуждение, только монада IO не чиста. монады вроде Моноды записи /T/Reader/T/State/T/ST чисто функциональный.

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

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

Ответ 6

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

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