add documentation about closure recursion
Haldean Brown
5 years ago

0 | Recursive closures ===================================================== | |

1 | Haldean Brown First draft: Nov 2016 | |

2 | Last updated: Nov 2016 | |

3 | ||

4 | Status: Draft | |

5 | ||

6 | ------------------------------------------------------------------------ | |

7 | ||

8 | The closure transformation turns closures into partially-applied | |

9 | functions, by turning values that have been closed over into arguments | |

10 | to the function itself. The specific algorithm for doing this is | |

11 | detailed greatly in the header closure.c, but the general gist is that: | |

12 | ||

13 | It transforms this: | |

14 | \x -> (\y -> + x y) | |

15 | To this: | |

16 | \x -> ((\x0 y -> + x0 y) x) | |

17 | ||

18 | It transforms this: | |

19 | \x -> (\y -> (\z -> x)) | |

20 | Into this: | |

21 | \x -> ((\x0 y -> ((\x1 z -> x1) x0)) x) | |

22 | ||

23 | It transforms this: | |

24 | \x -> { | |

25 | : y = + x 10 | |

26 | ! \z -> y | |

27 | } | |

28 | Into this: | |

29 | \x -> { | |

30 | : y = + x 10 | |

31 | ! (\y0 z -> y0) y | |

32 | } | |

33 | ||

34 | This closes these functions over the enclosing scope by making all | |

35 | enclosing scope information an explicit argument to the function, and | |

36 | then partially applying the function over that information. | |

37 | ||

38 | This document describes how the closure transformation interacts with | |

39 | recursion for values that are not bound to a global name. For example, | |

40 | this snippet: | |

41 | ||

42 | ! { | |

43 | : t = \x -> ? { | |

44 | . eq x 0 => "ok\n" | |

45 | . => t 0 | |

46 | } | |

47 | ! t 1 | |

48 | } | |

49 | ||

50 | In this example, the closure transformation should take t and turn it | |

51 | into this: | |

52 | ||

53 | : t = (\t x -> ? { | |

54 | . eq x 0 => "ok\n" | |

55 | . => t 0 | |

56 | }) t | |

57 | ||

58 | But now we find ourselves referencing t before we've defined it, and we | |

59 | can quickly get into a circular reference. Here, we transform t into a | |

60 | top-level anonymous function with its own value: | |

61 | ||

62 | : anonymous-t = | |

63 | \t x -> ? { | |

64 | . eq x 0 => "ok\n" | |

65 | . => t 0 | |

66 | } | |

67 | ||

68 | ! { | |

69 | : t = anonymous-t anonymous-t | |

70 | ! t 1 | |

71 | } | |

72 | ||

73 | In so doing, we can fully define anonymous-t without any | |

74 | self-references, and ditto with t. Note that in the actual | |

75 | implementation of this feature, anonymous-t does not have a name in the | |

76 | global namespace; it is fully anonymous and is only defined by its | |

77 | value. |