X-Git-Url: http://lambda.jimpryor.net/git/gitweb.cgi?p=lambda.git;a=blobdiff_plain;f=monad_transformers.mdwn;h=a1e6d45efce280ea0a963e35c16cd827ea740d75;hp=57affe5995da3cd4b2cc918b1d4270132825ee9a;hb=f4457664b4e5de53cff4bd079b8ea561ae66f1f0;hpb=4bab63e9b62e289b7feeae89cea4a1e27a0fe0f1 diff --git a/monad_transformers.mdwn b/monad_transformers.mdwn index 57affe59..a1e6d45e 100644 --- a/monad_transformers.mdwn +++ b/monad_transformers.mdwn @@ -116,6 +116,10 @@ Then if you want to use an `S`-specific monad like `puts succ` inside `MS`, you' # MS.(...elevate (S.puts succ) ...) +Each monad transformer's `elevate` function will be defined differently. They have to obey the following laws: + +* `Outer.elevate (Inner.unit a) <~~> Outer.unit a` +* `Outer.elevate (Inner.bind u f) <~~> Outer.bind (Outer.elevate u) (fun a -> Outer.elevate (f a))` We said that when T encloses M, you can rely on T's interface to be most exposed. That is intuitive. What you cannot also assume is that the implementing type has a Tish structure surrounding an Mish structure. Often it will be reverse: a ListT(Maybe) is implemented by a `'a list option`, not by an `'a option list`. Until you've tried to write the code to a monadic transformer library yourself, this will probably remain counter-intuitive. But you don't need to concern yourself with it in practise. Think of what you have as a ListT(Maybe); don't worry about whether the underlying implementation is as an `'a list option` or an `'a option list` or as something more complicated. @@ -135,6 +139,8 @@ Apart from whose interface is outermost, the behavior of a StateT(Maybe) and a M # module SM = S.T(Maybe_monad);; # MS.(run (elevate (S.puts succ) >> zero () >> elevate S.get >>= fun cur -> unit (cur+10) )) 0;; - : int option * S.store = (None, 1) + # MS.(run (elevate (S.puts succ) >> zero () >> elevate (S.put 5) )) 0;; + - : unit option * S.store = (None, 1) Although we have a wrapped `None`, notice that the store (as it was at the point of failure) is still retrievable. @@ -154,7 +160,7 @@ When Maybe is on the inside, on the other hand, a failure means the whole comput Exception: Failure "bye". --> -Here's an example wrapping List around Maybe, and vice versa: +Here's an example wrapping Maybe around List, and vice versa: # module LM = List_monad.T(Maybe_monad);; # module ML = Maybe_monad.T(List_monad);; @@ -186,7 +192,7 @@ This is fun. Notice the difference it makes whether the second `plus` is native # LL.(run(plus (unit 1) (unit 2) >>= fun i -> plus (unit i) (unit(10*i)) ));; - : ('_a, int) LL.result = \[[1; 10; 2; 20]] # LL.(run(plus (unit 1) (unit 2) >>= fun i -> elevate L.(plus (unit i) (unit(10*i)) )));; - - : ('_a, int) LL.result = \[[1; 2]; [1; 20]; [10; 2]; [10; 20]] + - : ('_a, int) LL.result = [[1; 2]; [1; 20]; [10; 2]; [10; 20]]