Writing a solution to "Data Types a la Carte"'s problem usine Purescript Run


I’m re-explaining the “Data Types a la Carte” paper in my learning repo. I’m also trying to teach (and learn by doing so) how to use VariantF and ultimately purescript-run to solve its problem.

Having read xgrommx’s code, which removes ValueF as a data type and reduces it to a smart constructor via pure

…I’ve written this code:

Unfortunately, I’m not sure how to evaluate (add (value 1) (value 2)) to 3.


The run combinator let you evaluate your set of functors in terms of some Monad m. There’s no combinator currently equivalent to iter from your linked example. However it can easily be written in terms of Run.resume Left Right and you’d get the same thing. If you wanted to use run you would have to use Identity as your m.


Thanks for your help! I’m looking into this now.


I’ve been banging my head at this for the past hour, but still haven’t gotten it to work. Sigh…

I realized that Run.resume Left Right is the definition of Run.peel. With this code:

iter :: forall r a. (VariantF r a -> a) -> Run r a -> a
iter k = go
  go m = case peel m of
    Left f -> k (go <$> f)
    Right a -> a

eval :: forall r a b
      . ((VariantF () a -> b) -> VariantF r Int -> Int)
     -> Run r a
     -> Int
eval algebra = iter (case_ # algebra)

-- Examples
main :: Effect Unit
main = do
  _ <- eval addAlgebra example_add
  pure unit

I get a compiler error because eval expects the a type in its Run r a argument to be Int, not a. However, the a type in the add function is another Run (ADD + r) Int. I’m not sure how I’d fix that since the code should work if I wrapped another add in there (e.g. add example_add (value 5)


If you have m (m a) and you want m a, then that’s exactly what Monad gives you through join.

add :: forall r
     . Run (ADD + r) Int
    -> Run (ADD + r) Int
    -> Run (ADD + r) Int
add x y = join $ lift _add (AddF x y)


:man_facepalming: Duh!

I started thinking I would need to define an Eval type class that uses instance chains like Coproduct does to inject a data type into it.

Thank you again!


It finally works! Thank you!