
On Fri, Sep 29, 2017 at 2:56 AM Viktor Dukhovni
Can you explain that qualification?
I mean that you don't need to use (>>=) on the IO inside the RowParser. The composition of two Applicatives is also an Applicative. If you upgrade one to Monad this is no longer true. Since you're only using (>>) (which is really an Applicative operation in disguise), we don't need to worry here.
Indeed this works, and looks more clear than some new unfamiliar operator. This seems to have no measurable run-time cost. Is it reasonable to expect that under the covers no objects boxed as (Compose _) are ever created, and that Compose here is just compile-time syntactic sugar for applying (*>) at the desired layer, so that:
getCompose $ Compose (Foo Bar a) *> Compose (Foo Bar b) *> Compose (Foo Bar c) ... *> Compose (Foo Bar z)
just compiles down to Foo (Bar a *> Bar b *> Bar c *> ... *> Bar z)? Where, in my case, Foo is "RowParser" and Bar is IO?
If we tried to write a typeclass instance for "composition of applicatives", it might look something like this: instance (Applicative f, Applicative g) => forall a. Applicative (f (g a)) where ... But we're not allowed to write such an instance. To get around this, a newtype is created: newtype Compose f g a = Compose { getCompose :: f (g a) } and a valid instance can be written: instance (Applicative f, Applicative g) => Applicative (Compose f g) where pure = Compose . pure . pure a <*> b = Compose $ liftA2 (<*>) a b You are correct in assuming it has no runtime cost- at runtime the `f (g a)` is passed around as normal, but at compile time, `Compose f g a` is considered distinct to `f (g a)`. Due to this typeclass instance, getCompose $ Compose a *> Compose b *> Compose c is equivalent to liftA2 (*>) (liftA2 (*>) a b) c