// Here's a helper that composes UpdateState with Leaf and // Branch in the original unlabeled tree. This looks very // hairy in C#, but in Haskell it's quite short. Here's what // we do with leaves: // // > mkm :: Tr anytype -> Labeled (Lt anytype) // > mkm (Lf x) // > = do n <- updateState -- call updateState; "n" is of type "S" // > return (Lf (n,x)) -- "return" does the heavy lifting // > -- of creating the Monad from a value. // // The "do" notation is just Haskell syntactic sugar for // precisely the following call of @bind: // // updateState >>= \n -> return (Lf (n, x)) // // which says "call update state, which returns an instance of // the state monad, then @bind it to the variable n in a // function that returns a leaf node labeled by the given // state value." We translate this directly into C# below. // // The Branch case is a trivial recursion. Notice that // updateState only gets called on leaves. // // > mkm (Br l r) // > = do l' <- mkm l // > r' <- mkm r // > return (Br l' r') // // Notice this is private: private static SM <Tr <Scp <a> > > MkM <a>(Tr <a> t) { if (t is Lf <a> ) { // Call UpdateState to get an instance of // SM<int>. Shove it (@bind it) through a lambda // expression that converts ints to SM<Tr<Scp<a>> // using the "closed-over" contents from the input // Leaf node: var lf = (t as Lf <a>); return(SM <int> .@bind (UpdateState(), (n => SM <Tr <Scp <a> > > .@return (new Lf <Scp <a> > { contents = new Scp <a> { label = n, lcpContents = lf.contents } } ) ) )); } else if (t is Br <a> ) { var br = (t as Br <a>); var oldleft = br.left; var oldright = br.right; return(SM <Tr <Scp <a> > > .@bind (MkM <a>(oldleft), (newleft => SM <Tr <Scp <a> > > .@bind (MkM <a>(oldright), (newright => SM <Tr <Scp <a> > > .@return (new Br <Scp <a> > { left = newleft, right = newright } ) ) ) ) )); } else { throw new Exception("MakeMonad/MLabel: impossible tree subtype"); } }