Ответ 1
Выполнение этого в Spider
выглядит невозможным. Internal
рассуждения впереди.
В реализации Spider
Reflex
одним из возможных Behavior
является вытягивание значения.
data Behavior a
= BehaviorHold !(Hold a)
| BehaviorConst !a
| BehaviorPull !(Pull a)
A Pull
значение ed состоит из того, как вычислить значение, когда необходимо, pullCompute
и кешированное значение, чтобы избежать ненужных повторений -comput, pullValue
.
data Pull a
= Pull { pullValue :: !(IORef (Maybe (PullSubscribed a)))
, pullCompute :: !(BehaviorM a)
}
Игнорирование уродливой среды BehaviorM
, liftIO
позволяет вывести вычисление IO
очевидным образом, он запускает его, когда BehaviorM
необходимо отбирать. В Pull
ваше поведение наблюдается один раз, но не наблюдается повторно, потому что кешированное значение не является недействительным.
Кэш-память PullSubscribed a
состоит из значения a
, списка других значений, которые должны быть недействительными, если это значение равно недействительными и некоторыми скучными средствами управления памятью.
data PullSubscribed a
= PullSubscribed { pullSubscribedValue :: !a
, pullSubscribedInvalidators :: !(IORef [Weak Invalidator])
-- ... boring memory stuff
}
An Invalidator
- это квантифицированный Pull
, который достаточно, чтобы получить ссылку на память для рекурсивного чтения недействительных, чтобы сделать недействительными и записать кэшированные значение Nothing
.
Чтобы постоянно тянуть, мы хотели бы иметь возможность постоянно аннулировать наш собственный BehaviorM
. Когда выполняется, среда, переданная в BehaviorM
, имеет копию собственного invalidator, которая используется зависимостями BehaviorM
, чтобы аннулировать ее, когда они сами стали недействительными.
Из внутренней реализации readBehaviorTracked
похоже, что поведение собственного invalidator (wi
) никогда не может закончиться в списке подписчиков, которые недействительны при его выборке (invsRef
).
a <- liftIO $ runReaderT (unBehaviorM $ pullCompute p) $ Just (wi, parentsRef)
invsRef <- liftIO . newIORef . maybeToList =<< askInvalidator
-- ...
let subscribed = PullSubscribed
{ pullSubscribedValue = a
, pullSubscribedInvalidators = invsRef
-- ...
}
Вне внутренних элементов, если существует способ постоянного выбора a Behavior
, он будет включать экземпляр MonadFix (PullM t)
или взаимную рекурсию через фиксацию Pull
и 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
, чтобы попробовать это, но я не думаю, что результаты будут хорошими.