Кто-либо когда-либо встречался с Преобразователем Монады в дикой природе?

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

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

Таким образом, я задаюсь вопросом: лучшая практика преобразователей Монады при контакте с теми упомянутыми выше общими задачами?

52
задан martingw 4 September 2016 в 03:37
поделиться

5 ответов

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

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

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

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

На практике я наблюдаю

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

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

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

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

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

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

43
ответ дан 7 November 2019 в 09:32
поделиться

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

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

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

2
ответ дан 7 November 2019 в 09:32
поделиться

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

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

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

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

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

8
ответ дан 7 November 2019 в 09:32
поделиться

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

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

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

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

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

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

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

2
ответ дан 7 November 2019 в 09:32
поделиться

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

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

3
ответ дан 7 November 2019 в 09:32
поделиться
Другие вопросы по тегам:

Похожие вопросы: