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

Generalize <@> #181

Open
mitchellwrosen opened this issue Jun 1, 2018 · 4 comments
Open

Generalize <@> #181

mitchellwrosen opened this issue Jun 1, 2018 · 4 comments

Comments

@mitchellwrosen
Copy link
Collaborator

When doing higher-order FRP, the Moment concept comes up often. It's similar to Behavior in that a Moment a represents an a that has a value at every point in time. (Aside: more documentation about this concept would be helpful; in the "model" implementation, Moment and Behavior are isomorphic, which is confusing).

For this reason I wonder if the <@> could/should be generalized to address both of these uses:

(<@>) :: Behavior (a -> b) -> Event a -> Event b
(<@>) :: Moment (a -> b) -> Event a -> Event b
@mitchellwrosen
Copy link
Collaborator Author

mitchellwrosen commented Jun 6, 2018

As a motivating example, here's a simple first-order rendering of some widgets:

-- render event and rendering function
eRender :: Event ()
render :: [Widget] -> IO ()
bScene :: Behavior [Widget]

reactimate (render <$> bScene <@ eRender)

Now say the widgets themselves are dynamic, so we move to higher-order combinators:

bScene :: Behavior [Behavior Widget]

reactimate (render <$> observeE ((valueB . sequenceA) <$> bScene <@ eRender))

This is the version I'd like to clean up, somehow, because I find it very difficult to read and understand.

One observation is that everything is much simpler in the Moment monad with do-notation, and there is not much need for <@> on Behavior, which can be written using valueB instead.

Instead of the above, I could drill down into the time-varying [Widget] to render like so:

mScene :: Moment [Widget]
mScene = do
  bWidgets <- valueB bScene
  valueB (sequenceA bWidgets)

The very last step of "sampling a time-varying thing when an event occurs" is where I could benefit from <@ on Moment, as:

reactimate (render <$> mScene <@ eRender)

But instead, I have to write:

reactimate (render <$> observeE (mScene <$ eRender))

@ChristopherKing42
Copy link

The term \m e -> observeE $ (\a -> m <*> pure a) <$> e seems to work.

@ocharles
Copy link
Collaborator

Personally I think using observeE is the way to go.

This is the version I'd like to clean up, somehow, because I find it very difficult to read and understand.

reactimate (render <$> observeE ((valueB . sequenceA) <$> bScene <@ eRender))

I would write this as:

reactimate $ observeE $ eRender $> do
  bWidgets <- valueB $ sequenceA bScene
  widgets <- valueB bWidgets
  return $ render widgets

@mitchellwrosen I'm generally pretty averse to type classes just for overloading. Is this something you strongly desire, or do you think using observeE (or generally working less point-free, like with your mScene snippet) is acceptable?

@mitchellwrosen
Copy link
Collaborator Author

@ocharles Good question... I too am generally averse to ad-hoc overloading, and it would also be nice not to make a beginner's first-order FRP experience more complicated in service of a power user who can wrangle higher-order FRP.

(Note: that ship has begun to sail anyway with the inclusion of Moment in the type of accumB)

That said, I feel the semantics and similarity between Moment and Behavior is captured very well by the generalization of <@>.

Moment and Behavior are in fact both conceptually identical - a value that varies over time. Such a thing can be sampled whenever an event fires at a particular moment in time - that's <@>!

The difference between Moment and Behavior only leaks through in combinators like changes and switchB, where it's relevant that Moment cannot efficiently communicate when its value changes. But that's definitely an irrelevant distinction if all you want to do is sample the time-varying value.

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

No branches or pull requests

3 participants