write-you-a-haskell/005_evaluation.md

560 lines
15 KiB
Markdown
Raw Normal View History

Squashed commit of the following: commit 41ba8c36a90cc11723b14ce6c45599eabdcfaa53 Author: Stephen Diehl <stephen.m.diehl@gmail.com> Date: Sun Jan 18 21:02:57 2015 -0500 type provenance commit be5eda941bb4c44b4c4af0ddbbd793643938f4ff Author: Stephen Diehl <stephen.m.diehl@gmail.com> Date: Sun Jan 18 20:13:06 2015 -0500 provenance prototype commit 7aa958b9c279e7571f7c4887f6aa19443e16f6fb Author: Stephen Diehl <stephen.m.diehl@gmail.com> Date: Sun Jan 18 19:35:08 2015 -0500 fix misc typos commit 52d60b3b2630e50ef0cd6ea5f0fa1f308d92e26d Author: Stephen Diehl <stephen.m.diehl@gmail.com> Date: Sun Jan 18 15:15:58 2015 -0500 license badge commit 7d34274afe6f05a0002c8f87e5077b6a130b42b4 Author: Stephen Diehl <stephen.m.diehl@gmail.com> Date: Sun Jan 18 15:07:28 2015 -0500 fix resolution for llvm cfg graphs commit 14d9bc836ecc64f8e9acc60bcbd2da02335255b9 Author: Stephen Diehl <stephen.m.diehl@gmail.com> Date: Sun Jan 18 13:12:39 2015 -0500 added codegen dsl stub commit 0f74cdd6f95d0a1fe1cafd73e45cb1407709efd8 Author: Stephen Diehl <stephen.m.diehl@gmail.com> Date: Sun Jan 18 13:01:14 2015 -0500 llvm cfg graphs commit a199d721503985954060e7670c1d2f5e1a65dd11 Author: Stephen Diehl <stephen.m.diehl@gmail.com> Date: Sun Jan 18 10:56:54 2015 -0500 source code font commit c7db0c5d67b73d8633f08be093971877e2d6ede0 Author: Stephen Diehl <stephen.m.diehl@gmail.com> Date: Sun Jan 18 09:59:37 2015 -0500 change phrasing around recursion commit 6903700db482524233262e722df54b1066218250 Author: Stephen Diehl <stephen.m.diehl@gmail.com> Date: Sat Jan 17 18:20:06 2015 -0500 contributors.md commit 14d90a3f2ebf7ddf1229c084fe4a1e9fa13f2e41 Author: Stephen Diehl <stephen.m.diehl@gmail.com> Date: Sat Jan 17 17:35:41 2015 -0500 added llvm logo commit d270df6d94cbf1ef9eddfdd64af5aabc36ebca72 Author: Stephen Diehl <stephen.m.diehl@gmail.com> Date: Sat Jan 17 15:50:28 2015 -0500 initial llvm chapter commit e71b189c057ea9e399e90e47d9d49bb4cf12cda8 Author: Stephen Diehl <stephen.m.diehl@gmail.com> Date: Sat Jan 17 12:21:00 2015 -0500 system-f typing rules commit 2a7d5c7f137cf352eeae64836df634c98118f594 Author: Stephen Diehl <stephen.m.diehl@gmail.com> Date: Thu Jan 15 15:21:14 2015 -0500 flesh out system-f commit 7b3b2f0a2aea5e1102abe093cf5e0559090720aa Author: Stephen Diehl <stephen.m.diehl@gmail.com> Date: Wed Jan 14 22:22:14 2015 -0500 started on extended parser commit cdeaf1a2658f15346fe1dc665ca09e954cce6c2e Author: Stephen Diehl <stephen.m.diehl@gmail.com> Date: Wed Jan 14 17:25:02 2015 -0500 creative commons license commit f09d210be253a05fc8ad0827cd72ffa32404e2ba Author: Stephen Diehl <stephen.m.diehl@gmail.com> Date: Wed Jan 14 16:54:10 2015 -0500 higher res images commit 8555eadfea8843f5683621e6652857e4259fa896 Author: Stephen Diehl <stephen.m.diehl@gmail.com> Date: Wed Jan 14 14:48:44 2015 -0500 cover page commit e5e542e92610f4bb4c5ac726ffa86cd1e07753e3 Author: Stephen Diehl <stephen.m.diehl@gmail.com> Date: Tue Jan 13 17:31:01 2015 -0500 initial happy/alex parser
2015-01-19 05:04:01 +03:00
<div class="pagetitle">
2015-01-06 18:09:41 +03:00
![](img/titles/evaluation.png)
Squashed commit of the following: commit 41ba8c36a90cc11723b14ce6c45599eabdcfaa53 Author: Stephen Diehl <stephen.m.diehl@gmail.com> Date: Sun Jan 18 21:02:57 2015 -0500 type provenance commit be5eda941bb4c44b4c4af0ddbbd793643938f4ff Author: Stephen Diehl <stephen.m.diehl@gmail.com> Date: Sun Jan 18 20:13:06 2015 -0500 provenance prototype commit 7aa958b9c279e7571f7c4887f6aa19443e16f6fb Author: Stephen Diehl <stephen.m.diehl@gmail.com> Date: Sun Jan 18 19:35:08 2015 -0500 fix misc typos commit 52d60b3b2630e50ef0cd6ea5f0fa1f308d92e26d Author: Stephen Diehl <stephen.m.diehl@gmail.com> Date: Sun Jan 18 15:15:58 2015 -0500 license badge commit 7d34274afe6f05a0002c8f87e5077b6a130b42b4 Author: Stephen Diehl <stephen.m.diehl@gmail.com> Date: Sun Jan 18 15:07:28 2015 -0500 fix resolution for llvm cfg graphs commit 14d9bc836ecc64f8e9acc60bcbd2da02335255b9 Author: Stephen Diehl <stephen.m.diehl@gmail.com> Date: Sun Jan 18 13:12:39 2015 -0500 added codegen dsl stub commit 0f74cdd6f95d0a1fe1cafd73e45cb1407709efd8 Author: Stephen Diehl <stephen.m.diehl@gmail.com> Date: Sun Jan 18 13:01:14 2015 -0500 llvm cfg graphs commit a199d721503985954060e7670c1d2f5e1a65dd11 Author: Stephen Diehl <stephen.m.diehl@gmail.com> Date: Sun Jan 18 10:56:54 2015 -0500 source code font commit c7db0c5d67b73d8633f08be093971877e2d6ede0 Author: Stephen Diehl <stephen.m.diehl@gmail.com> Date: Sun Jan 18 09:59:37 2015 -0500 change phrasing around recursion commit 6903700db482524233262e722df54b1066218250 Author: Stephen Diehl <stephen.m.diehl@gmail.com> Date: Sat Jan 17 18:20:06 2015 -0500 contributors.md commit 14d90a3f2ebf7ddf1229c084fe4a1e9fa13f2e41 Author: Stephen Diehl <stephen.m.diehl@gmail.com> Date: Sat Jan 17 17:35:41 2015 -0500 added llvm logo commit d270df6d94cbf1ef9eddfdd64af5aabc36ebca72 Author: Stephen Diehl <stephen.m.diehl@gmail.com> Date: Sat Jan 17 15:50:28 2015 -0500 initial llvm chapter commit e71b189c057ea9e399e90e47d9d49bb4cf12cda8 Author: Stephen Diehl <stephen.m.diehl@gmail.com> Date: Sat Jan 17 12:21:00 2015 -0500 system-f typing rules commit 2a7d5c7f137cf352eeae64836df634c98118f594 Author: Stephen Diehl <stephen.m.diehl@gmail.com> Date: Thu Jan 15 15:21:14 2015 -0500 flesh out system-f commit 7b3b2f0a2aea5e1102abe093cf5e0559090720aa Author: Stephen Diehl <stephen.m.diehl@gmail.com> Date: Wed Jan 14 22:22:14 2015 -0500 started on extended parser commit cdeaf1a2658f15346fe1dc665ca09e954cce6c2e Author: Stephen Diehl <stephen.m.diehl@gmail.com> Date: Wed Jan 14 17:25:02 2015 -0500 creative commons license commit f09d210be253a05fc8ad0827cd72ffa32404e2ba Author: Stephen Diehl <stephen.m.diehl@gmail.com> Date: Wed Jan 14 16:54:10 2015 -0500 higher res images commit 8555eadfea8843f5683621e6652857e4259fa896 Author: Stephen Diehl <stephen.m.diehl@gmail.com> Date: Wed Jan 14 14:48:44 2015 -0500 cover page commit e5e542e92610f4bb4c5ac726ffa86cd1e07753e3 Author: Stephen Diehl <stephen.m.diehl@gmail.com> Date: Tue Jan 13 17:31:01 2015 -0500 initial happy/alex parser
2015-01-19 05:04:01 +03:00
</div>
2015-01-06 18:09:41 +03:00
Squashed commit of the following: commit 41ba8c36a90cc11723b14ce6c45599eabdcfaa53 Author: Stephen Diehl <stephen.m.diehl@gmail.com> Date: Sun Jan 18 21:02:57 2015 -0500 type provenance commit be5eda941bb4c44b4c4af0ddbbd793643938f4ff Author: Stephen Diehl <stephen.m.diehl@gmail.com> Date: Sun Jan 18 20:13:06 2015 -0500 provenance prototype commit 7aa958b9c279e7571f7c4887f6aa19443e16f6fb Author: Stephen Diehl <stephen.m.diehl@gmail.com> Date: Sun Jan 18 19:35:08 2015 -0500 fix misc typos commit 52d60b3b2630e50ef0cd6ea5f0fa1f308d92e26d Author: Stephen Diehl <stephen.m.diehl@gmail.com> Date: Sun Jan 18 15:15:58 2015 -0500 license badge commit 7d34274afe6f05a0002c8f87e5077b6a130b42b4 Author: Stephen Diehl <stephen.m.diehl@gmail.com> Date: Sun Jan 18 15:07:28 2015 -0500 fix resolution for llvm cfg graphs commit 14d9bc836ecc64f8e9acc60bcbd2da02335255b9 Author: Stephen Diehl <stephen.m.diehl@gmail.com> Date: Sun Jan 18 13:12:39 2015 -0500 added codegen dsl stub commit 0f74cdd6f95d0a1fe1cafd73e45cb1407709efd8 Author: Stephen Diehl <stephen.m.diehl@gmail.com> Date: Sun Jan 18 13:01:14 2015 -0500 llvm cfg graphs commit a199d721503985954060e7670c1d2f5e1a65dd11 Author: Stephen Diehl <stephen.m.diehl@gmail.com> Date: Sun Jan 18 10:56:54 2015 -0500 source code font commit c7db0c5d67b73d8633f08be093971877e2d6ede0 Author: Stephen Diehl <stephen.m.diehl@gmail.com> Date: Sun Jan 18 09:59:37 2015 -0500 change phrasing around recursion commit 6903700db482524233262e722df54b1066218250 Author: Stephen Diehl <stephen.m.diehl@gmail.com> Date: Sat Jan 17 18:20:06 2015 -0500 contributors.md commit 14d90a3f2ebf7ddf1229c084fe4a1e9fa13f2e41 Author: Stephen Diehl <stephen.m.diehl@gmail.com> Date: Sat Jan 17 17:35:41 2015 -0500 added llvm logo commit d270df6d94cbf1ef9eddfdd64af5aabc36ebca72 Author: Stephen Diehl <stephen.m.diehl@gmail.com> Date: Sat Jan 17 15:50:28 2015 -0500 initial llvm chapter commit e71b189c057ea9e399e90e47d9d49bb4cf12cda8 Author: Stephen Diehl <stephen.m.diehl@gmail.com> Date: Sat Jan 17 12:21:00 2015 -0500 system-f typing rules commit 2a7d5c7f137cf352eeae64836df634c98118f594 Author: Stephen Diehl <stephen.m.diehl@gmail.com> Date: Thu Jan 15 15:21:14 2015 -0500 flesh out system-f commit 7b3b2f0a2aea5e1102abe093cf5e0559090720aa Author: Stephen Diehl <stephen.m.diehl@gmail.com> Date: Wed Jan 14 22:22:14 2015 -0500 started on extended parser commit cdeaf1a2658f15346fe1dc665ca09e954cce6c2e Author: Stephen Diehl <stephen.m.diehl@gmail.com> Date: Wed Jan 14 17:25:02 2015 -0500 creative commons license commit f09d210be253a05fc8ad0827cd72ffa32404e2ba Author: Stephen Diehl <stephen.m.diehl@gmail.com> Date: Wed Jan 14 16:54:10 2015 -0500 higher res images commit 8555eadfea8843f5683621e6652857e4259fa896 Author: Stephen Diehl <stephen.m.diehl@gmail.com> Date: Wed Jan 14 14:48:44 2015 -0500 cover page commit e5e542e92610f4bb4c5ac726ffa86cd1e07753e3 Author: Stephen Diehl <stephen.m.diehl@gmail.com> Date: Tue Jan 13 17:31:01 2015 -0500 initial happy/alex parser
2015-01-19 05:04:01 +03:00
> *Well-typed programs cannot "go wrong".*
2015-01-11 23:18:10 +03:00
>
Squashed commit of the following: commit 41ba8c36a90cc11723b14ce6c45599eabdcfaa53 Author: Stephen Diehl <stephen.m.diehl@gmail.com> Date: Sun Jan 18 21:02:57 2015 -0500 type provenance commit be5eda941bb4c44b4c4af0ddbbd793643938f4ff Author: Stephen Diehl <stephen.m.diehl@gmail.com> Date: Sun Jan 18 20:13:06 2015 -0500 provenance prototype commit 7aa958b9c279e7571f7c4887f6aa19443e16f6fb Author: Stephen Diehl <stephen.m.diehl@gmail.com> Date: Sun Jan 18 19:35:08 2015 -0500 fix misc typos commit 52d60b3b2630e50ef0cd6ea5f0fa1f308d92e26d Author: Stephen Diehl <stephen.m.diehl@gmail.com> Date: Sun Jan 18 15:15:58 2015 -0500 license badge commit 7d34274afe6f05a0002c8f87e5077b6a130b42b4 Author: Stephen Diehl <stephen.m.diehl@gmail.com> Date: Sun Jan 18 15:07:28 2015 -0500 fix resolution for llvm cfg graphs commit 14d9bc836ecc64f8e9acc60bcbd2da02335255b9 Author: Stephen Diehl <stephen.m.diehl@gmail.com> Date: Sun Jan 18 13:12:39 2015 -0500 added codegen dsl stub commit 0f74cdd6f95d0a1fe1cafd73e45cb1407709efd8 Author: Stephen Diehl <stephen.m.diehl@gmail.com> Date: Sun Jan 18 13:01:14 2015 -0500 llvm cfg graphs commit a199d721503985954060e7670c1d2f5e1a65dd11 Author: Stephen Diehl <stephen.m.diehl@gmail.com> Date: Sun Jan 18 10:56:54 2015 -0500 source code font commit c7db0c5d67b73d8633f08be093971877e2d6ede0 Author: Stephen Diehl <stephen.m.diehl@gmail.com> Date: Sun Jan 18 09:59:37 2015 -0500 change phrasing around recursion commit 6903700db482524233262e722df54b1066218250 Author: Stephen Diehl <stephen.m.diehl@gmail.com> Date: Sat Jan 17 18:20:06 2015 -0500 contributors.md commit 14d90a3f2ebf7ddf1229c084fe4a1e9fa13f2e41 Author: Stephen Diehl <stephen.m.diehl@gmail.com> Date: Sat Jan 17 17:35:41 2015 -0500 added llvm logo commit d270df6d94cbf1ef9eddfdd64af5aabc36ebca72 Author: Stephen Diehl <stephen.m.diehl@gmail.com> Date: Sat Jan 17 15:50:28 2015 -0500 initial llvm chapter commit e71b189c057ea9e399e90e47d9d49bb4cf12cda8 Author: Stephen Diehl <stephen.m.diehl@gmail.com> Date: Sat Jan 17 12:21:00 2015 -0500 system-f typing rules commit 2a7d5c7f137cf352eeae64836df634c98118f594 Author: Stephen Diehl <stephen.m.diehl@gmail.com> Date: Thu Jan 15 15:21:14 2015 -0500 flesh out system-f commit 7b3b2f0a2aea5e1102abe093cf5e0559090720aa Author: Stephen Diehl <stephen.m.diehl@gmail.com> Date: Wed Jan 14 22:22:14 2015 -0500 started on extended parser commit cdeaf1a2658f15346fe1dc665ca09e954cce6c2e Author: Stephen Diehl <stephen.m.diehl@gmail.com> Date: Wed Jan 14 17:25:02 2015 -0500 creative commons license commit f09d210be253a05fc8ad0827cd72ffa32404e2ba Author: Stephen Diehl <stephen.m.diehl@gmail.com> Date: Wed Jan 14 16:54:10 2015 -0500 higher res images commit 8555eadfea8843f5683621e6652857e4259fa896 Author: Stephen Diehl <stephen.m.diehl@gmail.com> Date: Wed Jan 14 14:48:44 2015 -0500 cover page commit e5e542e92610f4bb4c5ac726ffa86cd1e07753e3 Author: Stephen Diehl <stephen.m.diehl@gmail.com> Date: Tue Jan 13 17:31:01 2015 -0500 initial happy/alex parser
2015-01-19 05:04:01 +03:00
> <cite>— Robin Milner</cite>
2015-01-06 18:09:41 +03:00
<p class="halfbreak">
</p>
Evaluation
==========
While the lambda calculus is exceedingly simple, there is a great deal of
variety in ways to evaluate and implement the reduction of lambda expressions.
The different models for evaluation are *evaluation strategies*.
2015-01-06 18:09:41 +03:00
There is a bifurcation between two points in the design space: *strict* and
*non-strict* evaluation. An evaluation strategy is strict if the arguments to a
lambda expression are necessarily evaluated before a lambda is reduced. A
language in which the arguments are not necessarily evaluated before a lambda is
reduced is non-strict.
Squashed commit of the following: commit 41ba8c36a90cc11723b14ce6c45599eabdcfaa53 Author: Stephen Diehl <stephen.m.diehl@gmail.com> Date: Sun Jan 18 21:02:57 2015 -0500 type provenance commit be5eda941bb4c44b4c4af0ddbbd793643938f4ff Author: Stephen Diehl <stephen.m.diehl@gmail.com> Date: Sun Jan 18 20:13:06 2015 -0500 provenance prototype commit 7aa958b9c279e7571f7c4887f6aa19443e16f6fb Author: Stephen Diehl <stephen.m.diehl@gmail.com> Date: Sun Jan 18 19:35:08 2015 -0500 fix misc typos commit 52d60b3b2630e50ef0cd6ea5f0fa1f308d92e26d Author: Stephen Diehl <stephen.m.diehl@gmail.com> Date: Sun Jan 18 15:15:58 2015 -0500 license badge commit 7d34274afe6f05a0002c8f87e5077b6a130b42b4 Author: Stephen Diehl <stephen.m.diehl@gmail.com> Date: Sun Jan 18 15:07:28 2015 -0500 fix resolution for llvm cfg graphs commit 14d9bc836ecc64f8e9acc60bcbd2da02335255b9 Author: Stephen Diehl <stephen.m.diehl@gmail.com> Date: Sun Jan 18 13:12:39 2015 -0500 added codegen dsl stub commit 0f74cdd6f95d0a1fe1cafd73e45cb1407709efd8 Author: Stephen Diehl <stephen.m.diehl@gmail.com> Date: Sun Jan 18 13:01:14 2015 -0500 llvm cfg graphs commit a199d721503985954060e7670c1d2f5e1a65dd11 Author: Stephen Diehl <stephen.m.diehl@gmail.com> Date: Sun Jan 18 10:56:54 2015 -0500 source code font commit c7db0c5d67b73d8633f08be093971877e2d6ede0 Author: Stephen Diehl <stephen.m.diehl@gmail.com> Date: Sun Jan 18 09:59:37 2015 -0500 change phrasing around recursion commit 6903700db482524233262e722df54b1066218250 Author: Stephen Diehl <stephen.m.diehl@gmail.com> Date: Sat Jan 17 18:20:06 2015 -0500 contributors.md commit 14d90a3f2ebf7ddf1229c084fe4a1e9fa13f2e41 Author: Stephen Diehl <stephen.m.diehl@gmail.com> Date: Sat Jan 17 17:35:41 2015 -0500 added llvm logo commit d270df6d94cbf1ef9eddfdd64af5aabc36ebca72 Author: Stephen Diehl <stephen.m.diehl@gmail.com> Date: Sat Jan 17 15:50:28 2015 -0500 initial llvm chapter commit e71b189c057ea9e399e90e47d9d49bb4cf12cda8 Author: Stephen Diehl <stephen.m.diehl@gmail.com> Date: Sat Jan 17 12:21:00 2015 -0500 system-f typing rules commit 2a7d5c7f137cf352eeae64836df634c98118f594 Author: Stephen Diehl <stephen.m.diehl@gmail.com> Date: Thu Jan 15 15:21:14 2015 -0500 flesh out system-f commit 7b3b2f0a2aea5e1102abe093cf5e0559090720aa Author: Stephen Diehl <stephen.m.diehl@gmail.com> Date: Wed Jan 14 22:22:14 2015 -0500 started on extended parser commit cdeaf1a2658f15346fe1dc665ca09e954cce6c2e Author: Stephen Diehl <stephen.m.diehl@gmail.com> Date: Wed Jan 14 17:25:02 2015 -0500 creative commons license commit f09d210be253a05fc8ad0827cd72ffa32404e2ba Author: Stephen Diehl <stephen.m.diehl@gmail.com> Date: Wed Jan 14 16:54:10 2015 -0500 higher res images commit 8555eadfea8843f5683621e6652857e4259fa896 Author: Stephen Diehl <stephen.m.diehl@gmail.com> Date: Wed Jan 14 14:48:44 2015 -0500 cover page commit e5e542e92610f4bb4c5ac726ffa86cd1e07753e3 Author: Stephen Diehl <stephen.m.diehl@gmail.com> Date: Tue Jan 13 17:31:01 2015 -0500 initial happy/alex parser
2015-01-19 05:04:01 +03:00
Alternatively expressed, diverging terms are represented up to equivalence by
the *bottom* value, written as $\bot$. A function $f$ is non-strict if:
$$
f \bot \neq \bot
$$
2015-01-06 18:09:41 +03:00
Evaluation Models
-----------------
2015-01-07 06:05:53 +03:00
There are many different models, and various hybrids thereof. We will consider three
2015-01-06 18:09:41 +03:00
dominant models:
2015-01-07 06:05:53 +03:00
* Call-by-value: arguments are evaluated before a function is entered
2015-02-14 18:11:43 +03:00
* Call-by-name: arguments are passed unevaluated
* Call-by-need: arguments are passed unevaluated but an expression is only evaluated
2015-01-07 06:05:53 +03:00
once and shared upon subsequent references
2015-01-06 18:09:41 +03:00
2015-01-07 22:07:07 +03:00
Given an expression $f x$ the reduction in different evaluation models proceeds
differently:
2015-01-06 18:09:41 +03:00
*Call-by-value*:
1. Evaluate $x$ to $v$
2. Evaluate $f$ to $\lambda y. e$
3. Evaluate $[y/v]e$
*Call-by-name*:
1. Evaluate $f$ to $\lambda y. e$
2. Evaluate $[y/x]e$
*Call-by-need*:
1. Allocate a thunk $v$ for $x$
2. Evaluate $f$ to $\lambda y. e$
3. Evaluate $[y/v]e$
Terms that have a normal form in one model, may or may not have a normal form in
another. In call-by-need and call-by-name evaluation diverging terms are not
necessarily evaluated before entry, so some terms that have a normal form in
these models may diverge under call-by-value.
Call-by-value
-------------
Call by value is an extremely common evaluation model. Many programming
languages both imperative and functional use this evaluation strategy. The
2015-01-07 06:05:53 +03:00
essence of call-by-value is that there are two categories of expressions: *terms*
2015-01-06 18:09:41 +03:00
and *values*. Values are lambda expressions and other terms which are in normal
2015-01-07 06:05:53 +03:00
form and cannot be reduced further. All arguments to a function will be reduced to
2015-01-06 18:09:41 +03:00
normal form *before* they are bound inside the lambda and reduction only
2015-01-07 06:05:53 +03:00
proceeds once the arguments are reduced.
2015-01-06 18:09:41 +03:00
For a simple arithmetic expression, the reduction proceeds as follows. Notice
how the subexpression ``(2 + 2)`` is evaluated to normal form before being
bound.
```haskell
2015-02-14 18:11:43 +03:00
(\x. \y. y x) (2 + 2) (\x. x + 1)
=> (\x. \y. y x) 4 (\x. x + 1)
=> (\y. y 4) (\x. x + 1)
=> (\x. x + 1) 4
2015-01-06 18:09:41 +03:00
=> 4 + 1
=> 5
```
2015-01-09 07:37:53 +03:00
Naturally there are two evaluation rules for applications.
2015-01-06 18:09:41 +03:00
$$
\begin{array}{cl}
\displaystyle \frac{e_1 \to e_1'}{e_1 e_2 \to e_1' e_2} & \trule{E-App1} \\ \\
\displaystyle \frac{e_2 \to e_2'}{v_1 e_2 \to v_1 e_2'} & \trule{E-App2} \\ \\
\displaystyle {(\lambda x . e) v \to [x / v] e } & \trule{E-AppLam} \\ \\
\end{array}
$$
For a simple little lambda calculus the call-by-value interpreter is quite
simple. Part of the runtime evaluation of lambda calculus involves the creation
2015-01-07 06:05:53 +03:00
of *closures*, environments which hold the local variables in scope. In our
2015-01-06 18:09:41 +03:00
little language there are two possible values which reduction may converge on,
2015-01-07 06:05:53 +03:00
**VInt** and **VClosure**.
2015-01-06 18:09:41 +03:00
```haskell
data Expr
= Var Int
| Lam Expr
| App Expr Expr
| Lit Int
| Prim PrimOp Expr Expr
deriving Show
data PrimOp = Add | Mul
deriving Show
data Value
= VInt Int
| VClosure Expr Env
deriving Show
type Env = [Value]
emptyEnv :: Env
emptyEnv = []
```
2015-01-07 06:05:53 +03:00
The evaluator function simply maps the local scope and a term to the final
value. Whenever a variable is referred to it is looked up in the environment.
Whenever a lambda is entered it extends the environment with the local scope of
2015-01-06 18:09:41 +03:00
the closure.
```haskell
eval :: Env -> Expr -> Value
eval env term = case term of
Var n -> env !! n
Lam a -> VClosure a env
App a b ->
let VClosure c env' = eval env a in
let v = eval env b in
eval (v : env') c
Lit n -> VInt n
Prim p a b -> (evalPrim p) (eval env a) (eval env b)
evalPrim :: PrimOp -> Value -> Value -> Value
evalPrim Add (VInt a) (VInt b) = VInt (a + b)
2015-01-07 06:05:53 +03:00
evalPrim Mul (VInt a) (VInt b) = VInt (a * b)
2015-01-06 18:09:41 +03:00
```
Call-by-name
------------
2015-01-07 06:05:53 +03:00
In call-by-name evaluation, the arguments to lambda expressions are substituted
2015-01-06 18:09:41 +03:00
as is, evaluation simply proceeds from left to right substituting the outermost
lambda or reducing a value. If a substituted expression is not used it is never
evaluated.
$$
\begin{array}{cl}
\displaystyle \frac{e_1 \to e_1'}{e_1 e_2 \to e_1' e_2} & \trule{E-App} \\ \\
2015-02-14 18:11:43 +03:00
\displaystyle {(\lambda x . e_1) e_2 \to [x / e_2] e_1 } & \trule{E-AppLam} \\ \\
2015-01-06 18:09:41 +03:00
\end{array}
$$
For example, the same expression we looked at for call-by-value has the same
normal form but arrives at it by a different sequence of reductions:
```haskell
2015-02-14 18:11:43 +03:00
(\x. \y. y x) (2 + 2) (\x. x + 1)
=> (\y. y (2 + 2)) (\x. x + 1)
=> (\x. x + 1) (2 + 2)
2015-01-06 18:09:41 +03:00
=> (2 + 2) + 1
=> 4 + 1
=> 5
```
Squashed commit of the following: commit 41ba8c36a90cc11723b14ce6c45599eabdcfaa53 Author: Stephen Diehl <stephen.m.diehl@gmail.com> Date: Sun Jan 18 21:02:57 2015 -0500 type provenance commit be5eda941bb4c44b4c4af0ddbbd793643938f4ff Author: Stephen Diehl <stephen.m.diehl@gmail.com> Date: Sun Jan 18 20:13:06 2015 -0500 provenance prototype commit 7aa958b9c279e7571f7c4887f6aa19443e16f6fb Author: Stephen Diehl <stephen.m.diehl@gmail.com> Date: Sun Jan 18 19:35:08 2015 -0500 fix misc typos commit 52d60b3b2630e50ef0cd6ea5f0fa1f308d92e26d Author: Stephen Diehl <stephen.m.diehl@gmail.com> Date: Sun Jan 18 15:15:58 2015 -0500 license badge commit 7d34274afe6f05a0002c8f87e5077b6a130b42b4 Author: Stephen Diehl <stephen.m.diehl@gmail.com> Date: Sun Jan 18 15:07:28 2015 -0500 fix resolution for llvm cfg graphs commit 14d9bc836ecc64f8e9acc60bcbd2da02335255b9 Author: Stephen Diehl <stephen.m.diehl@gmail.com> Date: Sun Jan 18 13:12:39 2015 -0500 added codegen dsl stub commit 0f74cdd6f95d0a1fe1cafd73e45cb1407709efd8 Author: Stephen Diehl <stephen.m.diehl@gmail.com> Date: Sun Jan 18 13:01:14 2015 -0500 llvm cfg graphs commit a199d721503985954060e7670c1d2f5e1a65dd11 Author: Stephen Diehl <stephen.m.diehl@gmail.com> Date: Sun Jan 18 10:56:54 2015 -0500 source code font commit c7db0c5d67b73d8633f08be093971877e2d6ede0 Author: Stephen Diehl <stephen.m.diehl@gmail.com> Date: Sun Jan 18 09:59:37 2015 -0500 change phrasing around recursion commit 6903700db482524233262e722df54b1066218250 Author: Stephen Diehl <stephen.m.diehl@gmail.com> Date: Sat Jan 17 18:20:06 2015 -0500 contributors.md commit 14d90a3f2ebf7ddf1229c084fe4a1e9fa13f2e41 Author: Stephen Diehl <stephen.m.diehl@gmail.com> Date: Sat Jan 17 17:35:41 2015 -0500 added llvm logo commit d270df6d94cbf1ef9eddfdd64af5aabc36ebca72 Author: Stephen Diehl <stephen.m.diehl@gmail.com> Date: Sat Jan 17 15:50:28 2015 -0500 initial llvm chapter commit e71b189c057ea9e399e90e47d9d49bb4cf12cda8 Author: Stephen Diehl <stephen.m.diehl@gmail.com> Date: Sat Jan 17 12:21:00 2015 -0500 system-f typing rules commit 2a7d5c7f137cf352eeae64836df634c98118f594 Author: Stephen Diehl <stephen.m.diehl@gmail.com> Date: Thu Jan 15 15:21:14 2015 -0500 flesh out system-f commit 7b3b2f0a2aea5e1102abe093cf5e0559090720aa Author: Stephen Diehl <stephen.m.diehl@gmail.com> Date: Wed Jan 14 22:22:14 2015 -0500 started on extended parser commit cdeaf1a2658f15346fe1dc665ca09e954cce6c2e Author: Stephen Diehl <stephen.m.diehl@gmail.com> Date: Wed Jan 14 17:25:02 2015 -0500 creative commons license commit f09d210be253a05fc8ad0827cd72ffa32404e2ba Author: Stephen Diehl <stephen.m.diehl@gmail.com> Date: Wed Jan 14 16:54:10 2015 -0500 higher res images commit 8555eadfea8843f5683621e6652857e4259fa896 Author: Stephen Diehl <stephen.m.diehl@gmail.com> Date: Wed Jan 14 14:48:44 2015 -0500 cover page commit e5e542e92610f4bb4c5ac726ffa86cd1e07753e3 Author: Stephen Diehl <stephen.m.diehl@gmail.com> Date: Tue Jan 13 17:31:01 2015 -0500 initial happy/alex parser
2015-01-19 05:04:01 +03:00
Call-by-name is non-strict, although very few languages use this model.
2015-01-06 18:09:41 +03:00
Call-by-need
------------
*Call-by-need* is a special type of non-strict evaluation in which unevaluated
expressions are represented by suspensions or *thunks* which are passed into a
function unevaluated and only evaluated when needed or *forced*. When the thunk
is forced the representation of the thunk is *updated* with the computed value
and is not recomputed upon further reference.
2015-01-07 06:05:53 +03:00
The thunks for unevaluated lambda expressions are allocated when evaluated, and
the resulting computed value is placed in the same reference so that
2015-01-06 18:09:41 +03:00
subsequent computations share the result. If the argument is never needed it is
2015-01-08 05:33:59 +03:00
never computed, which results in a trade-off between space and time.
2015-01-06 18:09:41 +03:00
<!--
Evaluation for call-by-need never has worse asymptotic time complexity than
call-by-value, but can result in worse space complexity.
-->
2015-01-07 06:05:53 +03:00
Since the evaluation of subexpression does not follow any pre-defined order, any
impure functions with side-effects will be evaluated in an unspecified order. As
2015-01-06 18:09:41 +03:00
a result call-by-need can only effectively be implemented in a purely functional
setting.
```haskell
type Thunk = () -> IO Value
data Value
= VBool Bool
| VInt Integer
| VClosure (Thunk -> IO Value)
```
```haskell
update :: IORef Thunk -> Value -> IO ()
update ref v = do
writeIORef ref (\() -> return v)
return ()
```
```haskell
force :: IORef Thunk -> IO Value
force ref = do
th <- readIORef ref
v <- th ()
update ref v
return v
```
```haskell
mkThunk :: Env -> String -> Expr -> (Thunk -> IO Value)
mkThunk env x body = \a -> do
a' <- newIORef a
eval ((x, a') : env) body
```
```haskell
eval :: Env -> Expr -> IO Value
eval env ex = case ex of
EVar n -> do
th <- lookupEnv env n
v <- force th
return v
ELam x e -> return $ VClosure (mkThunk env x e)
EApp a b -> do
VClosure c <- eval env a
c (\() -> eval env b)
EBool b -> return $ VBool b
EInt n -> return $ VInt n
EFix e -> eval env (EApp e (EFix e))
```
For example, in this model the following program will not diverge since the
omega combinator passed into the constant function is not used and therefore the
argument is not evaluated.
```haskell
omega = (\x -> x x) (\x -> x x)
test1 = (\y -> 42) omega
```
```haskell
omega :: Expr
omega = EApp (ELam "x" (EApp (EVar "x") (EVar "x")))
(ELam "x" (EApp (EVar "x") (EVar "x")))
test1 :: IO Value
test1 = eval [] $ EApp (ELam "y" (EInt 42)) omega
```
2015-01-07 06:05:53 +03:00
Higher Order Abstract Syntax (HOAS)
-----------------------------------
2015-01-06 18:09:41 +03:00
2015-01-12 02:19:30 +03:00
GHC Haskell being a rich language has a variety of extensions that, among other
2015-01-06 18:09:41 +03:00
things, allow us to map lambda expressions in our defined language directly onto
lambda expressions in Haskell. In this case we will use a GADT to embed a
2015-01-07 06:05:53 +03:00
Haskell expression inside our expression type.
2015-01-06 18:09:41 +03:00
```haskell
{-# LANGUAGE GADTs #-}
data Expr a where
Lift :: a -> Expr a
Tup :: Expr a -> Expr b -> Expr (a, b)
Lam :: (Expr a -> Expr b) -> Expr (a -> b)
App :: Expr (a -> b) -> Expr a -> Expr b
Fix :: Expr (a -> a) -> Expr a
```
The most notable feature of this encoding is that there is no distinct
2015-01-07 06:05:53 +03:00
constructor for variables. Instead they are simply values in the host
2015-01-06 18:09:41 +03:00
language. Some example expressions:
```haskell
id :: Expr (a -> a)
id = Lam (\x -> x)
tr :: Expr (a -> b -> a)
2015-01-08 05:33:59 +03:00
tr = Lam (\x -> (Lam (\y -> x)))
2015-01-06 18:09:41 +03:00
fl :: Expr (a -> b -> b)
2015-01-08 05:33:59 +03:00
fl = Lam (\x -> (Lam (\y -> y)))
2015-01-06 18:09:41 +03:00
```
Our evaluator then simply uses Haskell for evaluation.
```haskell
eval :: Expr a -> a
eval (Lift v) = v
eval (Tup e1 e2) = (eval e1, eval e2)
eval (Lam f) = \x -> eval (f (Lift x))
eval (App e1 e2) = (eval e1) (eval e2)
eval (Fix f) = (eval f) (eval (Fix f))
```
Some examples of use:
```haskell
fact :: Expr (Integer -> Integer)
fact =
Fix (
Lam (\f ->
Lam (\y ->
Lift (
if eval y == 0
then 1
else eval y * (eval f) (eval y - 1)))))
test :: Integer
test = eval fact 10
main :: IO ()
main = print test
```
2015-01-07 06:05:53 +03:00
Several caveats must be taken when working with HOAS. First of all, it takes more
2015-01-06 18:09:41 +03:00
work to transform expressions in this form since in order to work with the
expression we would need to reach under the lambda binder of a Haskell function
itself. Since all the machinery is wrapped up inside of Haskell's implementation
even simple operations like pretty printing and writing transformation passes
can be more difficult. This form is a good form for evaluation, but not for
transformation.
2015-01-07 06:05:53 +03:00
Parametric Higher Order Abstract Syntax (PHOAS)
-----------------------------------------------
2015-01-06 18:09:41 +03:00
2015-01-07 06:05:53 +03:00
A slightly different form of HOAS called PHOAS uses a lambda representation
2015-01-08 05:33:59 +03:00
parameterized over the binder type under an existential type.
2015-01-06 18:09:41 +03:00
```haskell
{-# LANGUAGE RankNTypes #-}
data ExprP a
= VarP a
| AppP (ExprP a) (ExprP a)
| LamP (a -> ExprP a)
| LitP Integer
newtype Expr = Expr { unExpr :: forall a . ExprP a }
```
2015-01-07 06:05:53 +03:00
The lambda in our language is simply a lambda within Haskell. As an example,
2015-01-06 18:09:41 +03:00
the usual SK combinators would be written as follows:
```haskell
2015-01-11 21:52:00 +03:00
-- i x = x
2015-01-06 18:09:41 +03:00
i :: ExprP a
i = LamP (\a -> VarP a)
2015-01-11 21:52:00 +03:00
-- k x y = x
2015-01-06 18:09:41 +03:00
k :: ExprP a
k = LamP (\x -> LamP (\y -> VarP x))
2015-01-11 21:52:00 +03:00
-- s f g x = f x (g x)
2015-01-06 18:09:41 +03:00
s :: ExprP a
2015-01-11 21:52:00 +03:00
s =
LamP (\f ->
LamP (\g ->
LamP (\x ->
AppP
(AppP (VarP f) (VarP x))
(AppP (VarP g) (VarP x))
)))
2015-01-06 18:09:41 +03:00
```
Evaluation will result in a runtime ``Value`` type, just as before with our
2015-02-14 18:11:43 +03:00
outer interpreters. We will use several "extractor" functions which use
2015-01-06 18:09:41 +03:00
incomplete patterns under the hood. The model itself does not prevent malformed
programs from blowing up here, and so it is necessary to guarantee that the
program is sound before evaluation. Normally this would be guaranteed at a
higher level by a typechecker before even reaching this point.
```haskell
data Value
= VLit Integer
| VFun (Value -> Value)
fromVFun :: Value -> (Value -> Value)
fromVFun val = case val of
VFun f -> f
_ -> error "not a function"
fromVLit :: Value -> Integer
fromVLit val = case val of
VLit n -> n
2015-02-14 18:11:43 +03:00
_ -> error "not an integer"
2015-01-06 18:09:41 +03:00
```
Evaluation simply exploits the fact that nestled up under our existential type
is just a Haskell function and so we get all the name capture, closures and
binding machinery for free. The evaluation logic for PHOAS model is extremely
short.
```haskell
eval :: Expr -> Value
eval e = ev (unExpr e) where
ev (LamP f) = VFun(ev . f)
ev (VarP v) = v
ev (AppP e1 e2) = fromVFun (ev e1) (ev e2)
ev (LitP n) = VLit n
```
2015-01-08 05:33:59 +03:00
Consider the ``S K K = I`` example again and check the result:
2015-01-06 18:09:41 +03:00
```haskell
skk :: ExprP a
skk = AppP (AppP s k) k
example :: Integer
example = fromVLit $ eval $ Expr (AppP skk (LitP 3))
```
2015-01-07 06:13:06 +03:00
We will use this evaluation technique extensively in writing interpreters for
2015-01-06 18:09:41 +03:00
our larger languages. It is an extremely convenient and useful method for
writing interpreters in Haskell.
Embedding IO
------------
As mentioned before, effects are first class values in Haskell.
2015-01-07 06:05:53 +03:00
In Haskell we don't read from a file directly, but create a value that represents
reading from a file. This allows us to very cleanly model an interpreter for
2015-01-06 18:09:41 +03:00
our language inside of Haskell by establishing a mapping between the base
operations of our language and existing function implementations of the
standard operations in Haskell, and using monadic operations to build up a
2015-01-07 06:05:53 +03:00
pure effectful computation as a result of interpretation. After
evaluation, we finally lift the resulting IO value into Haskell and execute the
2015-01-06 18:09:41 +03:00
results. This fits in nicely with the PHOAS model and allows us to
2015-01-07 06:05:53 +03:00
efficiently implement a fully-fledged interpreter for our language with
2015-01-06 18:09:41 +03:00
remarkably little code, simply by exploiting Haskell's implementation.
To embed IO actions inside of our interpreter we create a distinct ``VEffect``
2015-01-07 06:05:53 +03:00
value that will build up a sequenced IO computation during evaluation. This
value will be passed off to Haskell and reified into real world effects.
2015-01-06 18:09:41 +03:00
```haskell
data ExprP a
= VarP a
| GlobalP Name
| AppP (ExprP a) (ExprP a)
| LamP (a -> ExprP a)
| LitP Char
| EffectP a
data Value
= VChar Char
| VFun (Value -> Value)
| VEffect (IO Value)
| VUnit
fromVEff :: Value -> (IO Value)
fromVEff val = case val of
VEffect f -> f
2015-02-14 18:11:43 +03:00
_ -> error "not an effect"
2015-01-06 18:09:41 +03:00
```
```haskell
eval :: Expr -> Value
eval e = ev (unExpr e) where
ev (LamP f) = VFun(ev . f)
ev (AppP e1 e2) = fromVFun (ev e1) (ev e2)
ev (LitP n) = VChar n
ev (EffectP v) = v
ev (VarP v) = v
ev (GlobalP op) = prim op
-- Lift an effect from our language into Haskell IO.
run :: Expr -> IO ()
run f = void (fromVEff (eval f))
```
2015-01-07 06:05:53 +03:00
The ``prim`` function will simply perform a lookup on the set of builtin
2015-01-06 18:09:41 +03:00
operations, which we'll define with a bit of syntactic sugar for wrapping up
Haskell functions.
```haskell
unary :: (Value -> Value) -> Value
unary f = lam $ \a -> f a
binary :: (Value -> Value -> Value) -> Value
binary f = lam $ \a ->
lam $ \b -> f a b
prim :: Name -> Value
prim op = case op of
"putChar#" -> unary $ \x ->
VEffect $ do
putChar (fromVChar x)
return VUnit
"getChar#" -> VEffect $ do
val <- getChar
return (VChar val)
"bindIO#" -> binary $ \x y -> bindIO x y
"returnIO#" -> unary $ \x -> returnIO x
"thenIO#" -> binary $ \x y -> thenIO x y
```
For example ``thenIO#`` sequences effects in our language will simply squash two
``VEffect`` objects into one composite effect building up a new ``VEffect``
value that is using Haskell's monadic sequencing on the internal ``IO`` value.
```haskell
bindIO :: Value -> Value -> Value
bindIO (VEffect f) (VFun g) = VEffect (f >>= fromVEff . g)
thenIO :: Value -> Value -> Value
thenIO (VEffect f) (VEffect g) = VEffect (f >> g)
returnIO :: Value -> Value
returnIO a = VEffect $ return a
```
Effectively we're just recreating the same conceptual relationship that Haskell
IO has with its runtime, but instead our host language uses Haskell as the
2015-01-06 18:09:41 +03:00
runtime!
Full Source
2015-01-09 07:37:53 +03:00
-----------
2015-01-06 18:09:41 +03:00
**Evaluation**
* [Call-by-value](https://github.com/sdiehl/write-you-a-haskell/blob/master/chapter6/interp.hs)
* [Call-by-need](https://github.com/sdiehl/write-you-a-haskell/blob/master/chapter6/lazy.hs)
**Higher Order Interpreters**
* [HOAS](https://github.com/sdiehl/write-you-a-haskell/blob/master/chapter6/hoas.hs)
* [PHOAS](https://github.com/sdiehl/write-you-a-haskell/blob/master/chapter6/phoas.hs)
* [Embedding IO](https://github.com/sdiehl/write-you-a-haskell/blob/master/chapter6/io.hs)
2015-01-09 07:46:30 +03:00
\pagebreak