
The basic idea is that you can define recursive functions using
recursive types.  If you want a function t1 -> t2, you define the
type:

T = mu a. a -> t1 -> t2

Then you can define a function that takes itself as its first
argument, having the type (T -> t1 -> t2). Note that T unrolls to
(T -> t1 -> t2), so if f : T, then (unroll(f)f) : t1 -> t2.

The trickest part is making sure that your definition has the right
termination behavior.  If you're not careful, the definition itself
loops, instead of giving a recursive function.

Here is some SML code you may use:


| EL.Dfun (fid, id, dom, cod, body) =>
     let
        val dom' = elabTp ctx ectx dom
        val cod' = elabTp ctx ectx cod

        val vrec = newvar ()
        val varg = newvar ()
        val ctx' = extendType (extendType ctx vrec (Carrow (dom', cod'))) varg dom'

        val ectx' =
           Resolve.append ectx
           (Cpair (Cunit, Cunit),
            Mpair (Min (VAL fid, Mval (Tvar vrec)),
                   Min (VAL id, Mval (Tvar varg))),
            Ssigma (Snamed (VAL fid, Sval (Carrow (dom', cod'))),
                    Snamed (VAL id, Sval (liftCon 1 dom'))))

        val (cod'', body') = elabTerm ctx' ectx' body

        val () = equiv ctx' cod' cod'' Ktype

        val vself = newvar ()
        val vbinds = newvar ()
        val c =
           compactCon
           (Crec (Carrow (Cvar (0, NONE),
                          Carrow (liftCon 1 dom', liftCon 1 cod'))))

        val e =
           Tlet (vself,
                 Troll (Tlam (vself, c,
                              Tlam (varg,
                                    compactCon dom',
                                    Tlet (vrec,
                                          Tapp (Tunroll (Tvar vself), Tvar vself),
                                          body'))),
                        c),
                 Tapp (Tunroll (Tvar vself), Tvar vself))
     in
        (Snamed (VAL fid, Sval (Carrow (dom', cod'))),
         Min (VAL fid, Mval e))
     end
