natefaubion / purescript-run

An extensible-effects implementation
MIT License
158 stars 14 forks source link

Observing changes in the State effect #18

Closed alexjg closed 6 years ago

alexjg commented 6 years ago

I'm using the Run.State effect in a program I'm writing. My entire application is run in a coroutine and I want to observe changes to the state in one of those coroutines in order to provide it as an input to the root Halogen component of my application. Basically what I want to do is write a function that interprets the state effect whilst publishing changes to the coroutine. Something like the following (I think):

handleState :: (AppState -> Aff ()) -> Run (state :: (RS.STATE AppState) | r) ~> Run (aff :: AFF| r)

Where the first argument is the function to dispatch to the coroutine.

I can see how I would implement this with my own custom state type. But is there anyway to add this functionality to the state effect that comes with purescript-run?

natefaubion commented 6 years ago

The State effect encapsulates the state :: (s -> Tuple a s) -> m a function, in that get/put/modify are all represented with the same constructor.

Given

data State s a = State (s -> s) (s -> a)

The first argument is a state transformation, and the second adapts the return type. So

get = State identity identity
put a = State (const a) (const unit)
modify f = State f (const unit)

The only way to distinguish between the operations would be to apply the transformation, and use unsafeRefEq. Parametricity ensures that a get operation must return the same argument.

But maybe it would be better for you to write something like:

State s a = Get (s -> a) | Modify (s -> s) a

Where you have the distinction built in to the effect.

alexjg commented 6 years ago

Ah okay, that makes sense, I'll roll my own. Thanks :).