Stefan O'Rear wrote:
apfelmus wrote:
>>
My assumption is that we have an equivalence

  forall a,b . m (a -> m b) ~ (a -> m b)

because any side effect executed by the extra m on the outside can well be delayed until we are supplied a value a. Well, at least when all arguments are fully applied, for some notion of "fully applied"

I figured that wouldn't be a problem since our values don't escape, and
the functions we define all respect the embedding... More formally:

Projections and injections:
  proj :: Monad m => m (a -> m b) -> (a -> m b)
proj ma = \x -> ma >>= \fn' -> fn' x
inj  fn = return fn

Define an equivalence relation:

ma ≡ mb <-> proj ma = proj mb
>
Projection respects equivalence:

ma ≡ mb -> proj ma = proj mb            (intro ->)
ma ≡ mb => proj ma = proj mb            (equiv def)
proj ma = proj mb => proj ma = proj mb  (assumption)

Application respects equivalence:

Yeah, that's the right approach, but it has a few typos. The correct version is

 (@) :: Monad m => m (a -> m b) -> m a -> m b
 (@) ma = \x -> x >>= proj ma

Formulating (@) in terms of proj ma is a very clever idea since it follows immediately that

 ma @ x = ma' @ x  iff  proj ma = proj ma'  iff  ma ≡ ma'

In other words, when viewed through @ and proj only, equivalent actions give equivalent results.


The main point is that this does not hold for the other curry-friendly type m a -> m b

 proj :: Monad m => (m a -> m b) -> (a -> m b)
 proj f = f . return

 (@) :: Monad m => (m a -> m b) -> m a -> m b
 (@) = id

 ma ≡ ma'  iff  proj ma = proj ma'

since those functions may execute their argument multiple times. So, here's the counterexample

 once  :: Monad m => m A -> m A
 once = id

 twice :: Monad m => m A -> m A
 twice x = x >> once x

Now, we have

 proj once = return = proj twice

but

 effect :: IO ()   -- a given effect
 effect = putStrLn "Kilroy was here!"

 once  @ effect = effect
 ≠ twice @ effect = effect >> effect


The same can be done for several arguments, along the lines of

  proj2 :: m (a -> m (b -> m c)) -> (a -> b -> m c)
  proj2 f = proj . (proj f)

  app2 :: m (a -> m (b -> m c)) -> (m a -> m b -> m c)
  app2 f mx my
   = (f @ mx) @ my
   = my >>= proj (mx >>= proj f)
   = my >>= \y -> mx >>= \x -> proj2 f x y

and similar results.

Regards,
apfelmus

_______________________________________________
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe

Reply via email to