natefaubion / purescript-run

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

Run in parallel? #17

Closed roryc89 closed 6 years ago

roryc89 commented 6 years ago

We have a blocks of program we would like to run in parallel. Is there any way to perform this sort of logic with purescript-run?

I.e.:


handlerProgram :: forall effs.  A -> Run effs Result
handlerProgram a = do
   var1 <- sequentialAsyncEffect a -- sequential 

   {var2, var3} <- {var2:_, var3:_} -- parallel
      <$> parallelAsyncEffect1 var1
      <*> parallelAsyncEffect2 var1

   traversePar doSomethingElseParallel var3 -- also parallel
   ...

Any help would be greatly appreciated. So far we have only been able to interpret the program sequentially.

natefaubion commented 6 years ago

It's not possible to have blocks of parallel code like that in general because Run is open-world, and not all effects can be run in parallel and then joined. It's possible to fork (that's essentially what CHOICE gives you), but then resuming from a single point after some set of effects have completed always requires consideration. For example, if you run multiple STATE effects in parallel, how do you join the results? You might have to require a commutative Monoid for the state type then for it to make sense. Likewise with EXCEPT, how do you recover if one of your forks (or all of them) throws? Do you collect errors, discard errors, etc? You have to handle each case specifically according to the semantics you want, and there's no possible one-size-fits-all solution.

One option is to define a closed-world set of effects that are known to run in parallel with the semantics you want, and lift that into your Run effects.

newtype MyParEffects a =
  MyParEffect (FreeAp (Run (...)) a)

liftParEffects :: forall r a. MyParEffects a -> Run (par :: FProxy MyParEffects | r) a
liftParEffects = Run.lift (SProxy :: SProxy "par")

Your interpreter can than interpret the FreeAp of all the embedded Run effects in parallel.

An alternative would be to have only forking as an effect, and then also have some sort of coordination primitive like AVars to deal with joins.

roryc89 commented 6 years ago

Thanks a lot! This is just what we were looking for. I assume this can be closed then?