Conal Elliott's paper具有以下定义:
Future a = (Time, a)
Stepper :: a -> Event a -> Reactive a
Ev :: Future (Reactive a) -> Event a
never : Event a
instance Monad Reactive
rA :: Reactive String
rA = "IA" `Stepper` (Ev (1, "1A" `Stepper` never))
rB :: Reactive String
rB = "IB" `Stepper` (Ev (1, "1B" `Stepper` never))
rC1 :: Reactive String
rC1 = (++) <$> rA <*> rB
rC1 = "IAIB" `Stepper` (Ev (1, "IA1B" `Stepper` never))
我相信以上是正确的。
rC2 :: Reactive String
rC2 = rA >>= (\a -> (a++) <$> rB)
应该{{1}}吗?
根据本文中的定义,看来rC1 = rC2
将包含在"IA1B" and "1AIB"
中的"IAIB"
和"1A1B"
之间。
这是否违反Monad法rC2
? (<*>) = ap
不应该吗?否则我误会了。
答案 0 :(得分:1)
这个故事有两个错误。该问题给出的示例实际上仅公开了第一个,但是在研究该问题时,我发现了join
定义中的另一个更严重的错误。
第一个错误是较小的:它是关于同时处理事件的。您的race
函数可让您合并同时发生的事件。在(<*>)
中利用了这一点,但是在您定义join
时,These
情况假装左事件(内部事件)首先发生。因此,如果您考虑使用(<*>)
来实现join
,并且这两个行为具有同时发生的事件,则join
不会将它们合并。
在反应性行为的情况下,两个同时发生的事件与在时间上彼此非常接近的两个事件是无法区分的,无论如何,最后一个是获胜的,因此前一个是否出现在事件中并不重要。流与否。例如,如果您开始对事件进行计数,则此操作将无法解决,并且由此得出的结论是,不应对行为进行此类操作。
我认为法律中出现的=
符号常常是语法上的(如果您允许我这样称呼的话),而在各种情况下,例如更加灵活地阅读。它们通常是重合的,因此,除非您习惯于正式地思考问题,否则很难真正看到问题所在。
从这种角度来看,将其忽略为“不是bug”是合理的。似乎仍然可以对实现进行修复,以使法律在语法上适用。那会让每个人都感到高兴。
要了解第二个错误,您必须再次了解join :: Reactive (Reactive a) -> Reactive a
的含义。
r :: Reactive (Reactive a)
是一种不断发展的行为。有时您会得到行为x
(未显示其内部变化),然后是行为y
,然后是行为z
...因此,从概念上讲,它看起来像一系列行为
xxxxx...
yyyyy...
zzzzz...
...
如果我们将行为视为时间r :: Time -> (Time -> a)
的函数,则join
在时间r
对t
进行采样,这就是另一种行为r t :: Time -> a
,它本身就被采样了在时间t
:(join r) t = r t t
。换句话说,您采取对角线行为:
x
y
z
因此,如果我们回顾事件驱动的Reactive
的定义,自然就会在出现新行为时忘记事件。确实,本文中出现的join
的定义是通过与join <$> urr
竞争而实现的,它忘记了内部行为ur
。但是,这仅占对角线的一侧:
x
yy
zzz
由于Reactive
的行为是事件流,因此Reactive (Reactive a)
的内部流可以包含在流自身出现之前发生的事件。因此,当您获得Future (Reactive a)
时,还需要一种从Future
发生之前截断事件的方法:
actualize :: Future (Reactive a) -> Future (Reactive a)
-- Exercise for the reader
并在join
中的某个地方使用它。