polysemy-research / polysemy-zoo

:monkey::panda_face: Experimental, user-contributed effects and interpreters for polysemy
BSD 3-Clause "New" or "Revised" License
70 stars 20 forks source link

Add interpreters for Reader and State based on HList #18

Closed jhgarner closed 5 years ago

jhgarner commented 5 years ago

Normally, you would need to compose tons of runReader and runState functions for each type in your effect. runReaders and runStates are new functions which allow you to pass in an HList and automatically interpret all of the values inside. For reader or state heavy effects, this should cut down on boilerplate.

The Readers and States types are designed to decrease boilerplate in type signatures for similar circumstances.

I wasn't sure whether this belonged in Polysemy or Polysemy zoo, but I figured Polysemy zoo would be the safer one to go for.

isovector commented 5 years ago

Cool idea! Could we do this generically, ie:

type Effmap (e :: Type -> (Type -> Type) -> Type -> Type) (a :: [Type]) = TMap e a

runSeveral 
    :: (forall r k x. k -> Sem (e k ': r) x -> Sem r x) 
    -> HList t 
    -> Sem (TConcat (Effmap e t) r) a 
    -> Sem r a
runSeveral f (a ::: as) = runSeveral f as . f a
runSeveral _ HNil       = id

then we could get this behavior for other things too (runInput comes to mind)

jhgarner commented 5 years ago

Yes, that's a good catch. I added runSeveral and runConstInputs to the code. I also added TypeMap and TypeConcat to the export list since they might be useful to people using runSeveral. Was there a specific reason you had Effmap specialize TypeMap?

isovector commented 5 years ago

No specific reason, just I was reading the code quickly and didn't see Effmap!

One explicit design goal of this library is that everything should be modular. The effects and interpreters provided by the base libs aren't privileged in any way and shouldn't be considered special. For this reason, I'm hesitant to bake-in support for runState and runReader and runConstInput, etc. These are all just arbitrary interpretations of arbitrary effects, and I'm afraid that baking-in the interpretations into runSeveral will help cement them as "special" in people's minds.

So what do you think about just providing runSeveral in this PR, and giving examples of using it with runState et al. in the documentation?

jhgarner commented 5 years ago

That makes sense. Having the specializations is useful but if they're only one or two lines of code away then it isn't a big deal. The only reason I can think of to have them in here would be if we wanted a convention where interpreters should define an HList specialization whenever applicable. Defining them here would be like playing catch up for Reader, State, etc. Since this is the zoo library though, I can see why that wouldn't be the case.

isovector commented 5 years ago

Fantasic! Thanks so much!