Skip to content

Commit effe924

Browse files
author
doyougnu
committed
opt: more lambda lifting chapter
1 parent c73adc9 commit effe924

File tree

2 files changed

+54
-12
lines changed

2 files changed

+54
-12
lines changed

src/Optimizations/GHC_opt/lambda_lifting.rst

Lines changed: 50 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,24 @@
11
.. _Lambda Lifting Chapter:
22

3+
Local Variables
4+
.. |glift| replace:: ``g_lifted``
5+
36
`Lambda Lifting`
47
================
58

69
Lambda Lifting :cite:p:`lambdaLifting` is a classic rewriting technique that
7-
rewrites functions to avoid excess allocations. It optimizes function
8-
definitions by moving local functions to the global scope of the program;
9-
thereby closure allocations, and by adding parameters to the function definition
10-
to capture free variables.
10+
that avoids excess closure allocations. It avoids closure allocation by moving
11+
local functions to the global scope of the program, and by adding parameters to
12+
the function definition to capture free variables. Thus, when a lifted function
13+
is called no heap allocation is needed because the lifted function no longer
14+
contains closures, rather it only references global names.
1115

1216
A Working Example
1317
-----------------
1418

1519
Consider the following program [#]_:
1620

17-
.. exec::
18-
:context: true
19-
:process: haskell
20-
21-
module Main where
21+
.. code-block:: haskell
2222
2323
f :: Int -> Int -> Int
2424
f a 0 = a
@@ -27,17 +27,55 @@ Consider the following program [#]_:
2727
g 0 = a
2828
g n = 1 + g (n - 1)
2929
30-
main :: IO ()
31-
main = print $ f 10 100
30+
The function ``f`` defines one local function, ``g``, which appears as a free
31+
variable in ``f``. Similarly, the variable ``a`` is a free variable in ``g``. A
32+
lambda lifted ``g``, will convert all free variables in ``g`` to parameters.
33+
Thus |glift| turns into:
34+
35+
.. code-block:: haskell
36+
37+
g_lifted a 0 = a
38+
g_lifted a n = 1 + g (n - 1)
39+
40+
Now ``a`` is an input, which means that |glift| can be floated out of ``f``
41+
to the top level producing the final program:
42+
43+
.. code-block:: haskell
44+
45+
g :: Int -> Int -> Int
46+
g_lifted a 0 = a
47+
g_lifted a n = 1 + g (n - 1)
48+
49+
f :: Int -> Int -> Int
50+
f a 0 = a
51+
f a n = f (g_lifted a (n `mod` 2)) (n - 1)
52+
53+
This new program will be much faster because ``f`` becomes essentially
54+
non-allocating. Before the lambda lifting transformation ``f`` had to allocate a
55+
closure for ``g`` in order to pass ``a`` to ``g``. After the lambda lifting on
56+
``g`` this is no longer the case; |glift| is a top level function so ``f`` can
57+
simply reference it; no closures needed!
58+
59+
.. note::
60+
61+
The fundamental tradeoff is decreased heap allocation for an increase in
62+
function parameters at each call site. This means that lambda lifting is not
63+
always a performance win. See `When to Manually Apply Lambda Lifting`_ for
64+
guidance on recognizing when your program may benefit.
3265

3366

3467
How Lambda Lifting Works in GHC
3568
-------------------------------
3669

70+
GHC does have a lambda lifting pass in STG, however lambda lifting is not the
71+
default method GHC uses for handling local functions. GHC uses an alternative
72+
strategy called :term:`Closure Conversion`...
73+
3774

3875
Observing the Effect of Lambda Lifting
3976
--------------------------------------
4077

78+
4179
When to Manually Apply Lambda Lifting
4280
-------------------------------------
4381

@@ -88,5 +126,5 @@ and we can also run from cabal target!!
88126
:args: bench lethargy:tooManyClosures
89127

90128

91-
.. [#] This program comes from Sebastian Graf and Simon Peyton Jones
129+
.. [#] This program and example comes from Sebastian Graf and Simon Peyton Jones
92130
:cite:p:`selectiveLambdaLifting`; thank you for your labor!:

src/glossary.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,10 @@ Glossary
2020
<https://en.wikipedia.org/wiki/Closure_(computer_programming)>`_ entry for
2121
more.
2222

23+
Closure Conversion
24+
25+
Start here tomorrow!
26+
2327
CAF
2428

2529
A CAF, or Constant Applicative Form, is a Haskell value which contains no

0 commit comments

Comments
 (0)