re-xyr / cleff

Fast and concise extensible effects
https://hackage.haskell.org/package/cleff
BSD 3-Clause "New" or "Revised" License
105 stars 6 forks source link

Semantics of `interpose` #19

Open re-xyr opened 2 years ago

re-xyr commented 2 years ago

interpose currrently has the "local" semantics of swapping handlers. That is, effects introduced outside of the scope of interpose will not have their dependency handlers swapped. This allows us to "overlay" behaviors on existing handlers.

However, it is also useful to have the "global" semantics of swapping handlers: all effects, in scope or out of scope, will have their dependency handlers swapped. This behavior is crucial in the implementation of scoped effects.

replace :: e :> es => Handler e es -> Eff es ~> Eff es
replace handle m = Eff \es@(Env _ re _) ->
  let ix = Rec.index re
  in unEff m $ updateEnv ix (mkInternalHandler ix es m)
re-xyr commented 2 years ago

It will be interesting to change the signature of interpret and interpose to

interpret :: Handler e (e : es) -> Eff (e : es) ~> Eff es
interpose :: e :> es => Handler e (e : es) -> Eff es ~> Eff es

So that the replace function can be used to implement the toEffWith functions. There will be possible performance degradation though so we need to benchmark first.

Another problem is that this introduces problem for interpose: any call to the "overlaid" effect need to be wrapped in raise. This is not a performance concern but certainly not good ergonomics.


No - this is a terrible idea. Effect handlers calling themselves recursively is minimally useful and can confuse newbies. toEffWith is already expressive enough.