Search code examples
purescriptset-union

(PureScript) How to create a Union of two separately defined rows of effects


I'm essentially needing to know how to write a function like this...

joinCommands :: forall e1 e2 e3
   . Union e1 e2 e3
  => Eff e1 Unit
  -> Eff e2 Unit
  -> Eff e3 Unit
joinCommands fn1 fn2 = do
  fn1
  fn2

Which doesn't work. I get this error:

[PureScript] Could not match kind

Control.Monad.Eff.Effect

with kind

Type

More specifically, what I'm trying to do is combine two Arrays of user-supplied functionality. That is one part of the codebase (user supplied) returns Array (Eff e1 Unit) and another part (also user supplied) returns Array (Eff e2 Unit). And at the application's entrypoint (the "core" unaccessable to the user) those two sets need to combined so they can be run together. So really, I'm trying to write a function of type Array (Eff e1 Unit) -> Array (Eff e2 Unit) -> Array (Eff e3 Unit) where e3 unites all the effects of e1 and e2.


Solution

  • I figured it out. For the general case, I just needed to specific that each Eff has a type that is compatiable with each other (not necessarily the same).

    joinCommands :: forall e. Eff e Unit -> Eff e Unit -> Eff e Unit
    joinCommands fn1 fn2 = do
      fn1
      fn2
    

    For the specific case, the answer is the same. The function signature would be forall e. Array (Eff e Unit) -> Array (Eff e Unit) -> Array (Eff e Unit) and the compiler can work out that the first set of Effs is compatible with the second set.

    So if you had...

    type Commands e = Array (Eff e Unit)
    a :: forall e. Commands (random :: RANDOM | e)
    a = []
    
    b :: forall e. Commands (now :: NOW | e)
    b = []
    
    c :: forall e. Commands e -> Commands e -> Commands e
    c = a <> b
    

    ... you can call c a b even though a and b both have different explicit effects.