Работа на пермутированном монадном трансформаторном стеке - PullRequest
15 голосов
/ 05 декабря 2011

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

fun = do
  lift a
  lift b
  c
  lift d
  lift e
  f

Я бы хотел написать эту функцию следующим образом:

fun = monadInvert $ do
  a
  b
  lift c
  d
  e
  lift f

Это вдвое уменьшает число lift с и делает код чище.

Вопрос: для каких монад возможна monadInvert? Как создать эту функцию?

Бонусные баллы: определите его для monad m, который является экземпляром MonadIO.

Название этого вопроса говорит о перестановках: действительно, как мы можем иметь дело с произвольными перестановками стека монадных трансформеров?

Ответы [ 3 ]

16 голосов
/ 05 декабря 2011

Ну, во-первых, вам не нужно так много подниматься. Для монадных трансформаторов выполняются следующие тождества:

lift c >>= lift . f = lift (c >>= f)
lift c1 >> lift c2  = lift (c1 >> c2)

Нередко пишется:

x <- lift $ do
    {- ... -}

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

c :: StateT MyState (ReaderT MyConfig SomeOtherMonad) Result
c = do
    x <- ask
    y <- get
    {- ... -}

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

10 голосов
/ 05 декабря 2011

Вас могут заинтересовать Монады, Молнии и Виды, Виртуализация стека Монад Тома Шрайверс и Бруно Оливейра.

Это не относится к вашей точке зрения о сокращении лифтов, но это интересный подход к вашей проблеме "перестановок монад".

Вот аннотация:

Эта работа направлена ​​на то, чтобы сделать монадические компоненты более пригодными для повторного использования и надежными. к изменениям, используя две новые технологии для виртуализации монады стек: монада молния и монада просмотров. Монада молния - это монада трансформатор, который создает виртуальные стеки монад, игнорируя определенные слои в бетонном стеке. Монада обеспечивает общую основу для виртуализации стека монад: они делают молния монады за один шаг далее и интегрировать его с широким спектром других виртуализаций. Например, определенные виды разрешают ограниченный доступ к монадам в стек. Кроме того, виды монад могут использоваться компонентами для обеспечить механизм вызова по ссылке для доступа к конкретным уровням стека монады. С этими двумя механизмами требования к компонентам с точки зрения формы стека монады больше не нужно буквально отражается в бетонном стеке монады, делая эти компоненты более многоразовый и устойчивый к изменениям.

1 голос
/ 18 января 2012

Я в основном уверен, что то, что вы описываете, невозможно для ввода-вывода, который всегда является самой внутренней монадой:

От Мартина Грабмюллера: «Монадные трансформаторы шаг за шагом», доступно http://www.grabmueller.de/martin/www/pub/

В этом документе мы вызываем liftIO в eval6 для выполнения действий ввода-вывода. Зачем нам поднимать в этом случае? Потому что нет класса IO для который мы можем создать экземпляр типа. Поэтому для действий ввода / вывода мы нужно вызвать лифт, чтобы отправить команды внутрь

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

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

...