Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature request: onDemand :: IO a -> Behavior x a #122

Open
achirkin opened this issue Jul 20, 2017 · 3 comments
Open

Feature request: onDemand :: IO a -> Behavior x a #122

achirkin opened this issue Jul 20, 2017 · 3 comments

Comments

@achirkin
Copy link

The point is to be able to run use a cheap IO a function to create a Behavior t a, which would lazily obtain current values whenever any event requires it. I see this question has been answered on stackoverflow from time to time, so I wonder what is the current state of the things?

I've been trying to workaround this for a while and came up with a seems-to-be-not-crashing solution. I posted it as an answer to one discussion.
Here is how it looks like:

import System.IO.Unsafe (unsafeInterleaveIO)
import qualified Reflex.Spider.Internal as Spider

onDemand :: IO a -> Behavior t a
onDemand ma = SpiderBehavior . Spider.Behavior . Spider.BehaviorM . ReaderT $ computeF
  where
    {-# NOINLINE computeF #-}
    computeF (Nothing, _) = unsafeInterleaveIO ma
    computeF (Just (invW,_), _) = unsafeInterleaveIO $ do
        toReconnect <- newIORef []
        _ <- Spider.invalidate toReconnect [invW]
        ma

So, the idea is to call invalidate function (with unsafeInterleaveIO) on current state as late as possible every time the value is requested.

Now, the question is if this code breaks something internally or not? :)
Related questions:

  • Is the list inside toReconnect always empty in current setting?
  • Is the returned WeakList of invalidators going to be empty in current setting in future?
@ryantrinkle
Copy link
Member

Won't this potentially return different two different values if two different events both ask for the value in the same frame? Also, i'm a bit unclear on why unsafeInterleaveIO is required - why not just compute the value directly?

@cgibbard
Copy link
Collaborator

cgibbard commented Jul 20, 2017 via email

@achirkin
Copy link
Author

Thanks for comments!

Surely, I don't pretend my code snipped should go into the library :) Thanks to unsafeInterleaveIO, the action happens when the value of Behavior is evaluated to WHNF, which looks totally non-deterministic. However, this is the only trick I found to invalidate an old cache value: PullSubscribed for a given behavior is created after the action is executed (cause it needs the action result), and unsafeInterleaveIO ensures invalidate is called after that (which would be impossible if you evaluated the content of the action to WHNF at the moment of creating PullSubscribed). Please correct me if this does not make sense!

Now, I am using this workaround in my library to get some really simple state information from JS side of the program, such as whether the CTRL key is pressed at the moment of a click event.
So, until reflex library has some smart way to create such behaviors, I would really like to know if my workaround can potentially break some event/switches due to not taking special care about content of toReconnect reference. Is that the case?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

5 participants