Gabriella439 / pipes

Compositional pipelines
BSD 3-Clause "New" or "Revised" License
487 stars 72 forks source link

MonadTrans instance is not law-abiding #179

Closed ElvishJerricco closed 8 years ago

ElvishJerricco commented 8 years ago

The simplest example is this: lift (return a) should equal return a. But, with Proxy, lift returns an M _, and return returns Pure. The free monad transformer falls to the same problem (which I'm sure you're aware of, as I believe you created that transformer; EDIT: "you" being Gabriel Gonzalez), so I'm tempted to say the solution would be similar to Free's.

That said, it could be a matter of observability. I'm not sure if it's actually possible to observe the difference, since I don't believe the constructors of Proxy are exported to external libraries. I just thought it was worth bringing up, in case it hadn't been noticed yet.

Gabriella439 commented 8 years ago

This is intentional, for performance reasons, and the design choice is documented in the module header of Pipes.Internal: https://hackage.haskell.org/package/pipes-4.2.0/docs/Pipes-Internal.html

The law-abiding solution is to make Proxy equivalent to something like this:

data ProxyF a' a b' b x = Request a' (a -> x) | Respond b (b' -> x)

type Proxy a' a b' b = FreeT (ProxyF a' a b' b)

... where FreeT is the one from the free library

The public pipes API (i.e. everything except Pipes.Internal) doesn't expose a way to detect the law violation and the speed-up from this internal "cheating" is significant.

ElvishJerricco commented 8 years ago

Cool. I figured.