暂停monad [英] The Pause monad
问题描述
但是,这是一个挑战:你可以创建一个monad,它可以暂停?$ / b>
数据暂停sx
实例Monad(暂停s)
mutate ::(s - > s) - >暂停s()
yield: :暂停s()
step :: s - >暂停s() - >(s,Maybe(暂停s()))
Pause
monad是一种状态monad(因此 mutate
,具有明显的语义)。通常像这样的monad具有某种运行功能,它运行计算并将您返回到最终状态。但是 Pause
是不同的:它提供了一个 step 函数,它运行计算直到它调用魔术
yield
函数。在这里计算暂停,返回给调用者足够的信息以便稍后恢复计算。
额外的awesomness:允许调用者修改步骤
呼叫。 (例如,上面的类型签名应该允许这样做。)
用例:编写代码通常很容易它做了一些复杂的事情,但是总的PITA将它转换为输出运行中的中间状态。如果您希望用户能够在执行过程的中途修改某些内容,那么情况会非常复杂。
实现思路: p>
-
很明显可以通过线程,锁和
IO
。但我们可以做得更好吗? ; - ) -
-
某种疯狂的事情可能会延续monad?
writer monad,其中
yield
只是记录当前状态,然后我们可以通过迭代伪装到 step 日志中的状态。 (很明显,这排除了改变步骤之间的状态,因为我们现在并没有真的暂停任何东西。) >解决方案
当然;您只需让任何计算结果结束,或者暂停自己,给出一个在简历中使用的动作,以及当时的状态:
数据暂停sa =暂停{runPause :: s - > (PauseResult s a,s)}
data PauseResult s a
=完成a
|暂停(暂停)
实例Monad(暂停)其中
返回a =暂停(\s - >(完成a,s))
m>> = k =暂停$ \s - >
案例runPause m s
(完成a,s') - > runPause(k a)s'
(Suspend m',s') - > (挂起(m'>> = k),s')
get ::暂停ss
get =暂停(\ s - >(完成s,s))
put :: s - >暂停s()
put s =暂停(\_ - >(Done(),s))
yield :: Pause s()
yield = Pause( \s->(Suspend(return()),s))
step :: Pause s() - > s - > (Maybe(Pause s()),s)
step m s =
case runPause m s
(Done _,s') - > (Nothing,s')
(暂停m',s') - > (Just m',s')
Monad
实例只是以正常方式对事物进行排序,并将最终结果传递给 k
继续,或者添加剩余的计算以完成暂停。
Monads can do many amazing, crazy things. They can create variables which hold a superposition of values. They can allow you to access data from the future before you compute it. They can allow you to write destructive updates, but not really. And then the continuation monad allows you to break people's minds! Ususally your own. ;-)
But here's a challenge: Can you make a monad which can be paused?
data Pause s x instance Monad (Pause s) mutate :: (s -> s) -> Pause s () yield :: Pause s () step :: s -> Pause s () -> (s, Maybe (Pause s ()))
The Pause
monad is a kind of state monad (hence mutate
, with the obvious semantics). Normally a monad like this has some sort of "run" function, which runs the computation and hands you back the final state. But Pause
is different: It provides a step
function, which runs the computation until it calls the magical yield
function. Here the computation is paused, returning to the caller enough information to resume the computation later.
For extra awesomness: Allow the caller to modify the state between step
calls. (The type signatures above ought to allow this, for example.)
Use case: It's often easy to write code that does something complex, but a total PITA to transform it to also output the intermediate states in its operation. If you want the user to be able to change something mid-way through execution, things get complex really fast.
Implementation ideas:
Obviously it can be done with threads, locks and
IO
. But can we do better? ;-)Something insane with a continuation monad?
Maybe some kind of writer monad, where
yield
just logs the current state, and then we can "pretend" tostep
it by iterating over the states in the log. (Obviously this precludes altering the state between steps, since we're not really "pausing" anything now.)
Sure; you just let any computation either finish with a result, or suspend itself, giving an action to be used on resume, along with the state at the time:
data Pause s a = Pause { runPause :: s -> (PauseResult s a, s) }
data PauseResult s a
= Done a
| Suspend (Pause s a)
instance Monad (Pause s) where
return a = Pause (\s -> (Done a, s))
m >>= k = Pause $ \s ->
case runPause m s of
(Done a, s') -> runPause (k a) s'
(Suspend m', s') -> (Suspend (m' >>= k), s')
get :: Pause s s
get = Pause (\s -> (Done s, s))
put :: s -> Pause s ()
put s = Pause (\_ -> (Done (), s))
yield :: Pause s ()
yield = Pause (\s -> (Suspend (return ()), s))
step :: Pause s () -> s -> (Maybe (Pause s ()), s)
step m s =
case runPause m s of
(Done _, s') -> (Nothing, s')
(Suspend m', s') -> (Just m', s')
The Monad
instance just sequences things in the normal way, passing the final result to the k
continuation, or adding the rest of the computation to be done on suspension.
这篇关于暂停monad的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!