Com S 641 meeting -*- Outline -*- * recursively defined abstractions (2.8) ** problem Q: Do the typing rules allow recursively-defined abstractions? no, because a binding isn't used in its own body ------------------------------------------ RECURSION IN ABSTRACTIONS (2.8) Is this legal? proc ohno = call ohno Type proof? |- call ohno: comm, if _________________________________________ |- proc ohno = call ohno:{ohno:comm}dec ------------------------------------------ put in the \emptyset as environment, ... (ohno:comm) \in \emptyset so this doesn't work ** solution ------------------------------------------ FIXING RECURSION IN ABSTRACTIONS Typing rule: |- C: comm __________________________________ pi |- rec-proc I = C : {I:comm}dec Semantics: [[pi |- rec-proc I = C:{I:comm}dec]]e s = ------------------------------------------ ... pi \unionMinus {I:comm} the point is that the type of I can be used in typing I use \unionMinus (unlike the book) to allow recursion in nested scopes, where the name redefines one in an outer scope. a disjoint union wouldn't nallow overriding of declarations from surrounding scopes {(I, p)}, where p(s') = [[pi \unionMinus {I:comm} |- C:comm]](e \unionMinus {(I, p)}) s' This can be understood as a family of approximations p_0(s) = _ p_1(s) = [[pi \unionMinus {I:comm} |- C:comm]](e \unionMinus {(I,p_0)}) s ... Thus, p(s') = s'' iff there is some k >= 0 such that p_k(s') = s'' Q: can we use the same idea for recursively-defined functions? yes ** variation of copy rule ------------------------------------------ UNFOLDING RULE FOR RECURSIVE ABSTRACTIONS Recursive syntax binder: rec-proc I = C ==> rec-fun I = E ==> Unfolding Rule: (rec I:comm . C) ==> (rec I:t exp . E) ==> ------------------------------------------ ... proc I = (rec I:comm . C) ... fun I = (rec I:t exp . E) but it's going to be hard to get the expressions to stop! ... [(rec I:comm . C)/call I] C ... [(rec I:t exp . E)/I] E ------------------------------------------ EXAMPLES (alias i = loc 1, alias o = loc 2); rec-proc fact = if @i = 0 then skip else (o := @o * @i; i := @i + -1; call fact) in o := 1; call fact ==> alias i = loc 1, alias o = loc 2, rec-proc fact = if @ = 0 then skip else ( := @ * @ ; := @ + -1; call fact) in loc 2 := 1; call fact ==> alias i = loc 1, alias o = loc 2, proc fact = (rec fact:comm . if @loc 1 = 0 then skip else (loc 2 := @loc 2 * @loc 1; loc 1 := @loc 1 + -1; call fact)) in loc 2 := 1; call fact ==> loc 2 := 1; (rec fact:comm . if @loc 1 = 0 then skip else (loc 2 := @loc 2 * @loc 1; loc 1 := @loc 1 + -1; call fact)) ==> loc 2 := 1; if @loc 1 = 0 then skip else (loc 2 := @loc 2 * @loc 1; loc 1 := @loc 1 + -1; (rec fact:comm . if @loc 1 = 0 then skip else (loc 2 := @loc 2 * @loc 1; loc 1 := @loc 1 + -1; call fact))) ==> ------------------------------------------ after substituting, unfold once Using the unfolding rule, copy rule, and core, we can understand the meaning of the program.