Реальная жизнь и полезные примеры монад Reverse State

Монада Reverse State — действительно хороший и умопомрачительный пример выразительности языка Haskell и ленивых вычислений. Но понять эту монаду не так просто. Более того, очень трудно найти убедительный пример из реальной жизни того, что с помощью монады Reverse State можно сделать проще, чем с любым другим инструментом языка.

Монада Reverse State определяется следующим образом:

newtype RState s a = RState { runRState :: s -> (a,s) }

instance Monad (RState s) where
    return x = RState $ (,) x
    RState sf >>= f = RState $ \s ->
        let (a, past)   = sf future
            (b, future) = runRState (f a) s
        in (b, past)

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

  1. Ответ Quora: хорошо объяснено и даже имеет реальный пример использования, но без кода, и неясно, действительно ли это хорошая идея использовать RState.
  2. Mindfuck: знакомство с этой красивой концепцией, но пример не полезно. Никто не будет писать числа Фибоначчи таким образом.
  3. Блог Кванга на Haskell: показывает, как Writer можно эмулировать с помощью RState но давай. Не совсем жизненный пример :)

Мне также известно о tardis. package, но нет учебника по этой библиотеке, примеры документации действительно абстрактны, не так много людей действительно это понимают. Ближе всего к тому, что мне нужно, это это руководство, но оно пример tardis, а не только RState. Так же, как ссылка на эту книгу.

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

Использовал ли кто-то эту монаду в реальной жизни или у него была действительно красивая и полезная иллюстрация с кодом?


person Shersh    schedule 30.04.2017    source источник
comment
Ваш пост кажется перевернутым форматом Stack Overflow. У вас есть ответ, и вы ищете вопрос. Этот сайт предназначен для реальных, практических вопросов, а не широких, спекулятивных.   -  person 4castle    schedule 01.05.2017
comment
@4castle, возможно, вы правы, но, по крайней мере, я нахожу эту тему достаточно интересной, чтобы сказать: в данном случае кого волнует формат Stack Overflow.   -  person leftaroundabout    schedule 01.05.2017
comment
Почему все должно иметь реальное применение? Разве вещи не могут быть просто крутыми, веселыми или красивыми?   -  person Benjamin Hodgson♦    schedule 01.05.2017
comment
@BenjaminHodgson Согласен. Более того, такие вещи часто становятся чрезвычайно полезными в какой-то момент, часто неожиданно.   -  person Petr    schedule 01.05.2017
comment
@BenjaminHodgson Конечно, все может быть круто, красиво и весело. Тем не менее, есть радость взять вещь, которая просто красива, и применить ее где-то в реальном мире, и заставить ее работать! И вы можете понять что-то более глубокое, если посмотрите на это с разных сторон, примеры из реального мира являются одним из таких углов.   -  person Shersh    schedule 01.05.2017
comment
Замените прошлое и будущее на x и y.   -  person    schedule 30.06.2018
comment
Версия этой монады используется для реализации Data.Traversable.mapAccumR.   -  person dfeuer    schedule 01.03.2019


Ответы (1)


Я знаю об этих монадах уже более десяти лет и только недавно увидел их реальное применение. Это немного в необычной обстановке. Мы с коллегой используем функциональное реактивное программирование через библиотеку «reflex» и работаем над библиотекой, помогающей создавать приложения для работы с терминальной графикой. Если вы знакомы с 'reflex-dom', он похож по своей природе, за исключением того, что наша базовая монада вместо того, чтобы помещать последующие виджеты один за другим в DOM, вместо этого просто складывает верхние «изображения» на основе символьных ячеек. друг друга, и пользователь должен разумно разделить экран. Мы хотели предоставить что-то более приятное, чем это, что в некоторой степени отслеживало бы оставшееся пространство на экране и позволяло бы пользователю размещать некоторые «плитки» в строках и столбцах, так что блок выполнения в основном соответствует либо столбец или ряд плиток на экране.

В дополнение к решению проблемы макета, мы также хотим, чтобы плитки могли управлять фокусом клавиатуры, позволяя пользователю нажимать клавишу Tab, чтобы циклически перемещаться по ним, или Shift-Tab, чтобы двигаться в обратном направлении. Именно здесь монадный преобразователь состояния вперед-назад во времени стал очень удобным: мы можем иметь текущее состояние в любом направлении как Событие (пустого кортежа). Каждая плитка может отправлять событие предыдущему и следующему виджетам (и получать от них событие), уведомляя виджеты, когда они получают фокус клавиатуры, и, таким образом, должна перестать блокировать нажатия клавиш от их дочерних виджетов. Итак, схематически виджет плитки выглядит примерно так:

do rec focusP <- recvFromPast
       sendToPast shiftTabPress
       tabPress <- gate focused $ ... filter input Event for Tab keypresses ...
       shiftTabPress <- gate focused $ ... filter input Event for Shift-Tab ...
       focused <- hold False $ leftmost
         [ True <$ (focusP <> focusF)
         , False <$ (shiftTabPress <> tabPress) ]
       v <- ... run the child widget and do layout stuff ...
       sendToFuture tabPress
       focusF <- recvFromFuture
   return v

Здесь sendToFuture — это обычное состояние «положить», sendToPast — это «положить» в обратном времени, recvFromPast — это обычное состояние «получить», а recvFromFuture — это «получить» в обратном времени. Таким образом, focusP :: Event t () — это Событие, которое мы получаем от нашего предшественника (вероятно, еще одна плитка, подобная этой), говорящее нам, что теперь у нас есть фокус, а focusF — это аналогичное Событие, которое мы получаем от нашего преемника. Мы отслеживаем, когда у нас есть фокус, используя «удержание» для создания focused :: Behavior t Bool, которое затем используется для блокировки событий клавиатуры, чтобы мы обязательно сообщали нашим соседям, что они получают фокус, только если мы сами сфокусированы, и также используется в бите, который я опустил, когда мы запускаем дочерний виджет, чтобы соответствующим образом фильтровать его входные события.

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

person Cale Gibbard    schedule 28.02.2019
comment
Потрясающий пример! - person Shersh; 25.03.2019