本文介绍了为持续可测量的现象创建行为的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧! 问题描述 29岁程序员,3月因学历无情被辞! 我想从 在 Spider 中执行此操作看起来不可能。 内部提前推理。 在 Spider Reflex ,其中一个可能的 行为 s将拉取该值。 数据行为a = BehaviorHold!(保留a) | BehaviorConst!a | BehaviorPull!(Pull a) A Pull ed值包含如何计算当需要时, pullCompute 和一个缓存的值以避免不必要的重新计算, pullValue 。 data pull a = Pull {pullValue ::!(IORef(Maybe(PullSubscribed a))),pullCompute ::!(BehaviorM a)} 忽略 BehaviorM , liftIO 以显而易见的方式提取 IO 计算,它在行为M 需要被抽样。在 Pull 中,您的行为会被观察一次,但不会被重新观察,因为缓存的值不会失效。 缓存值 PullSubscribed一个 包含值 a ,如果此值无效,则需要使其他值无效的列表以及一些无聊的内存管理的东西。 pre $ data pullSubscribed a = PullSubscribed {pullSubscribedValue ::!a , pullSubscribedInvalidators ::!(IORef [Weak Invalidator]) - ...无聊的内存} Invalidator 是一个量化的 Pull ,足以获得内存引用t o递归地读取invalidators来使失效并将缓存值写入 Nothing 。 能够不断使我们自己的 BehaviorM 失效。执行时,传递给 BehaviorM 的环境具有自己的invalidator副本,该副本由 BehaviorM 在它们自己变为无效时使它无效。 从内部执行 readBehaviorTracked 似乎没有办法行为本身的失效者( wi )最终会在取样者列表中被取消( invsRef )。 a< - liftIO $ runReaderT(unBehaviorM $ pullCompute p)$ Just(wi,parentsRef) invsRef - ... let subscribed = PullSubscribed {pullSubscribedValue = a ,pullSubscribedInvalidators = invsRef - ... } 在内部之外,如果确实存在一种方法来持续对 Behavior 它将涉及 MonadFix(PullM t)实例或通过修复 pull 和 sample : onDemand ::(Reflex t,MonadIO(PullM t))=> IO a - >行为ta onDemand read = b 其中b =拉出去去=做样品b liftIO读取 我没有 Reflex 环境来尝试此操作,但我不'我认为结果会很好。 I would like to create a Behavior t a from an IO a, with the intended semantics that the IO action would be run every time the behavior is sampled:{- language FlexibleContexts #-}import Reflex.Domimport Control.Monad.TransonDemand :: (MonadWidget t m, MonadIO (PullM t)) => IO a -> m (Behavior t a)I hoped I could do this by just executing the measurement in a pull:onDemand measure = return $ pull (liftIO measure)However, the resulting Behavior never changes after an initial measurement.The workaround I could come up with was to create a dummy Behavior that changes "frequently enough" and then create a fake dependency on that:import Data.Time.Clock as Timehold_ :: (MonadHold t m, Reflex t) => Event t a -> m (Behavior t ())hold_ = hold () . (() <$)onDemand :: (MonadWidget t m, MonadIO (PullM t)) => IO a -> m (Behavior t a)onDemand measure = do now <- liftIO Time.getCurrentTime tick <- hold_ =<< tickLossy (1/1200) now return $ pull $ do _ <- sample tick liftIO measureThis then works as expected; but since Behaviors can only be sampled on demand anyway, this shouldn't be necessary.What is the correct way to create a Behavior for a continuous, observable-at-any-time phenomenon? 解决方案 Doing this in Spider looks impossible. Internal reasoning ahead.In the Spider implementation of Reflex, one of the possible Behaviors is to pull the value.data Behavior a = BehaviorHold !(Hold a) | BehaviorConst !a | BehaviorPull !(Pull a)A Pulled value consists of how to compute the value when needed, pullCompute, and a cached value to avoid unnecessary re-computation, pullValue.data Pull a = Pull { pullValue :: !(IORef (Maybe (PullSubscribed a))) , pullCompute :: !(BehaviorM a) }Ignoring the ugly environment of BehaviorM, liftIO lifts an IO computation the obvious way, it runs it when the BehaviorM needs to be sampled. In the Pull, your behavior is observed once but isn't re-observed because the cached value isn't invalidated.The cached value PullSubscribed a consists of the value a, a list of other values that need to be invalidated if this value is invalidated, and some boring memory management stuff.data PullSubscribed a = PullSubscribed { pullSubscribedValue :: !a , pullSubscribedInvalidators :: !(IORef [Weak Invalidator]) -- ... boring memory stuff }An Invalidator is a quantified Pull that's enough to get the memory reference to recursively read the invalidators to invalidate and write the cached value to Nothing.To pull constantly we'd like to be able to constantly invalidate our own BehaviorM. When executed, the environment passed to the BehaviorM has a copy of its own invalidator, which is used by dependencies of the BehaviorM to invalidate it when they themselves become invalid.From the internal implementation of readBehaviorTracked there seems to be no way that the behavior's own invalidator (wi) can ever end up in the list of subscribers that are invalidated when it is sampled (invsRef). a <- liftIO $ runReaderT (unBehaviorM $ pullCompute p) $ Just (wi, parentsRef) invsRef <- liftIO . newIORef . maybeToList =<< askInvalidator -- ... let subscribed = PullSubscribed { pullSubscribedValue = a , pullSubscribedInvalidators = invsRef -- ... }Outside of the internals, if there does exist a way to constantly sample a Behavior it would involve a MonadFix (PullM t) instance or mutual recursion through fixing of pull and sample:onDemand :: (Reflex t, MonadIO (PullM t)) => IO a -> Behavior t aonDemand read = b where b = pull go go = do sample b liftIO readI don't have a Reflex environment to try this in, but I don't think the results will be pretty. 这篇关于为持续可测量的现象创建行为的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持! 上岸,阿里云!
09-02 22:20