@@ -22,7 +22,50 @@ Glossary
22
22
23
23
Closure Conversion
24
24
25
- Start here tomorrow!
25
+ Closure conversion is the default way GHC treats free variables in a
26
+ function body. Closure Conversion creates a top level record for the
27
+ original function, called the function environment, whose fields are the
28
+ free variables of the function. The environment is passed to the function
29
+ as an implicit parameter and the free variable call sites are rewritten as
30
+ field accesses. Then the function and the record are grouped in a tuple,
31
+ i.e., a closure (pair of environment and function) is created causing some
32
+ extra heap allocation. Finally the call sites of the original function are
33
+ rewritten to pass the environment with the original function. Consider
34
+ this example:
35
+
36
+ .. code-block :: haskell
37
+
38
+ ...
39
+ let f = foldl (\acc _ -> acc + x) y xs
40
+ in f [1..100]
41
+ ...
42
+
43
+ In this example ``x `` and ``y `` are free variables in the function ``f `` .
44
+ Closure conversion will capture them and transform this function to:
45
+
46
+ .. code-block :: haskell
47
+
48
+ ...
49
+ -- the function environment
50
+ data EnvF = EnvF { x :: Int, y :: Int }
51
+
52
+ -- the new function
53
+ f_cc env xs = foldl (\acc _ -> acc + x env) (y env) xs
54
+
55
+ -- the closure that replaces the original function in the same scope
56
+ let f = (f_cc, EnvF x y)
57
+ in (fst f) (snd f) [1..100]
58
+ ...
59
+
60
+ Notice closure conversion has *added * an extra ``let `` expression for the
61
+ closure and the reference to ``x `` and ``y `` have been replaced with
62
+ accesses to ``env `` . The let expression can be a source of extra heap
63
+ allocations and is one of the costs of closure conversion. However, the
64
+ benefits are uniformity; every function can be treated as a closure.
65
+ Closure conversion is often contrasted with Lambda Lifting which is
66
+ another strategy to handle free variables that does not incur extra heap
67
+ allocation. See :cite:t: `lambdaLifting ` and
68
+ :cite:t: `selectiveLambdaLifting ` for more.
26
69
27
70
CAF
28
71
@@ -38,6 +81,8 @@ Glossary
38
81
bar :: (Int, [Int])
39
82
bar = ((*) 10 10, [1..])
40
83
84
+ -- not a lambda, curried functions that can be reduced when given an
85
+ -- input are CAFs
41
86
baz :: Int -> Int
42
87
baz = (*) 3
43
88
@@ -46,7 +91,7 @@ Glossary
46
91
qux e = e * 3 -- equivalent to baz but is a lambda so not a CAF
47
92
48
93
quux :: Int -> Int
49
- quux = (*) 10 x -- x is free thus
94
+ quux = (*) x -- x is free thus not a CAF
50
95
51
96
These values are *constant * because they don't bind any variables or have
52
97
any free variables. Because they are constant they are floated (see
0 commit comments