Монады могут делать много удивительных, сумасшедших вещей. Они могут создавать переменные, которые содержат суперпозицию значений. Они могут позволить вам получить доступ к данным из будущего, прежде чем вы его вычислите. Они могут позволить вам писать деструктивные обновления, но не совсем. И тогда монада продолжения позволяет вам разбить людей! Усушно - собственный.; -)
Но вот вызов: Можете ли вы сделать монаду, которая может быть приостановлена?
data Pause s x instance Monad (Pause s) mutate :: (s -> s) -> Pause s () yield :: Pause s () step :: s -> Pause s () -> (s, Maybe (Pause s ()))
Монада Pause
- это своего рода государственная монада (следовательно, mutate
, с очевидной семантикой). Обычно такая монада имеет какую-то функцию "run", которая запускает вычисление и возвращает вам окончательное состояние. Но Pause
отличается: он предоставляет функцию step
, которая запускает вычисление, пока не назовет магическую функцию yield
. Здесь вычисление приостанавливается, возвращая вызывающему абоненту достаточно информации, чтобы возобновить вычисление позже.
Для дополнительной awesomness: Позволяет вызывающему абоненту изменять состояние между вызовами step
. (Например, надписи типов выше должны допускать это.)
Случай использования: часто бывает легко написать код, который делает что-то сложное, но полный PITA, чтобы преобразовать его, чтобы также выводить промежуточные состояния в его работу. Если вы хотите, чтобы пользователь мог что-то изменить в середине исполнения, все становится очень быстрым.
Идеи реализации:
-
Очевидно, это можно сделать с помощью потоков, блокировок и
IO
. Но можем ли мы сделать лучше?; -) -
Что-то не в порядке с монадой продолжения?
-
Может быть, какая-то писательская монада, где
yield
просто записывает текущее состояние, а затем мы можем "притворяться" наstep
, итерируя по состояниям в журнале. (Очевидно, это исключает изменение состояния между шагами, поскольку мы на самом деле не "приостанавливаем" что-либо сейчас.)