这样做在Spider
看起来不可能。Internal
提前推理。
In the Spider
实施Reflex
,其中一种可能的Behavior https://hackage.haskell.org/package/reflex/docs/Reflex-Spider-Internal.html#t:Behaviors是拉取值。
data Behavior a
= BehaviorHold !(Hold a)
| BehaviorConst !a
| BehaviorPull !(Pull a)
A Pull https://hackage.haskell.org/package/reflex/docs/Reflex-Spider-Internal.html#t:Pulled value 包括如何在需要时计算该值,pullCompute
,以及一个缓存值以避免不必要的重新计算,pullValue
.
data Pull a
= Pull { pullValue :: !(IORef (Maybe (PullSubscribed a)))
, pullCompute :: !(BehaviorM a)
}
忽略了恶劣的环境BehaviorM https://hackage.haskell.org/package/reflex/docs/Reflex-Spider-Internal.html#t:BehaviorM, liftIO
举起一个IO
计算的明显方式,它运行时BehaviorM
需要采样。在里面Pull
,您的行为会被观察一次,但不会再次被观察,因为缓存的值并未失效。
缓存的值PullSubscribed a https://hackage.haskell.org/package/reflex/docs/Reflex-Spider-Internal.html#t:PullSubscribed由值组成a
,如果该值无效则需要无效的其他值的列表,以及一些无聊的内存管理内容。
data PullSubscribed a
= PullSubscribed { pullSubscribedValue :: !a
, pullSubscribedInvalidators :: !(IORef [Weak Invalidator])
-- ... boring memory stuff
}
An Invalidator https://hackage.haskell.org/package/reflex/docs/Reflex-Spider-Internal.html#t:Invalidator是一个量化的Pull
这足以获取内存引用以递归地读取无效器以使其无效并将缓存的值写入Nothing
.
为了不断地拉动,我们希望能够不断地使我们自己的BehaviorM
。执行时,环境传递给BehaviorM
有一个自己的失效器的副本,由依赖项使用BehaviorM
当它们本身失效时使其失效。
从内部实现来看readBehaviorTracked https://hackage.haskell.org/package/reflex-0.4.0/docs/src/Reflex-Spider-Internal.html#readBehaviorTracked%5D似乎没有办法让行为自己的失效器(wi
) 可能会出现在采样时失效的订阅者列表中 (invsRef
).
a <- liftIO $ runReaderT (unBehaviorM $ pullCompute p) $ Just (wi, parentsRef)
invsRef <- liftIO . newIORef . maybeToList =<< askInvalidator
-- ...
let subscribed = PullSubscribed
{ pullSubscribedValue = a
, pullSubscribedInvalidators = invsRef
-- ...
}
在内部结构之外,如果确实存在一种方法来不断地采样Behavior
这将涉及MonadFix (PullM t)
实例或通过修复相互递归pull https://hackage.haskell.org/package/reflex-0.4.0/docs/Reflex-Class.html#v:pull and sample https://hackage.haskell.org/package/reflex-0.4.0/docs/Reflex-Class.html#v:sample:
onDemand :: (Reflex t, MonadIO (PullM t)) => IO a -> Behavior t a
onDemand read = b
where
b = pull go
go = do
sample b
liftIO read
我没有Reflex
尝试这个的环境,但我认为结果不会很好。