2020-11-03 15:52:04 -08:00
|
|
|
# Lambda Calculus
|
2020-11-02 15:59:35 -08:00
|
|
|
This is a simple implementation of the untyped lambda calculus
|
|
|
|
with an emphasis on clear, readable Haskell code.
|
2019-08-15 10:42:24 -07:00
|
|
|
|
|
|
|
## Usage
|
2021-03-05 23:38:21 -08:00
|
|
|
Run the program using `stack run` (or run the tests with `stack test`).
|
|
|
|
|
2019-08-15 10:42:24 -07:00
|
|
|
Type in your expression at the prompt: `>> `.
|
2021-03-05 23:38:21 -08:00
|
|
|
The expression will be evaluated to normal form using the call-by-value evaluation strategy and then printed.
|
2020-11-02 15:59:35 -08:00
|
|
|
Exit the prompt with `Ctrl-c` (or equivalent).
|
2019-08-19 15:08:45 -07:00
|
|
|
|
2019-08-21 15:18:25 -07:00
|
|
|
### Example session
|
2019-08-15 10:42:24 -07:00
|
|
|
```
|
2020-11-03 13:29:59 -08:00
|
|
|
>> let D = \x. x x; F = \f. f (f y) in D (F \x. x)
|
|
|
|
y y
|
|
|
|
>> let T = \f x. f (f x) in (\f x. T (T (T (T T))) f x) (\x. x) y
|
2019-08-15 13:11:17 -07:00
|
|
|
y
|
2020-11-02 15:59:35 -08:00
|
|
|
>> (\x y z. x y) y
|
2020-11-03 13:29:59 -08:00
|
|
|
λy' z. y y'
|
2020-11-03 15:52:04 -08:00
|
|
|
>> let fix = (\x. x x) \fix f x. f (fix fix f) x; S = \n f x. f (n f x); plus = fix \plus x. x S in plus (\f x. f (f (f x))) (\f x. f (f x)) f x
|
|
|
|
f (f (f (f (f x))))
|
2021-03-05 23:38:21 -08:00
|
|
|
>> y (callcc \k. (\x. (\x. x x) (\x. x x)) (k z))
|
|
|
|
y z
|
2019-08-21 15:18:25 -07:00
|
|
|
>> ^C
|
2019-08-15 10:42:24 -07:00
|
|
|
```
|
|
|
|
|
2019-08-21 15:18:25 -07:00
|
|
|
## Notation
|
|
|
|
[Conventional Lambda Calculus notation applies](https://en.wikipedia.org/wiki/Lambda_calculus_definition#Notation),
|
2020-11-02 15:59:35 -08:00
|
|
|
with the exception that variable names are multiple characters long,
|
2020-11-03 15:52:04 -08:00
|
|
|
`\` is permitted in lieu of `λ` to make it easier to type,
|
2020-11-02 15:59:35 -08:00
|
|
|
and spaces are used to separate variables rather than commas.
|
2019-08-21 15:18:25 -07:00
|
|
|
|
|
|
|
* Variable names are alphanumeric, beginning with a letter.
|
|
|
|
* Outermost parentheses may be dropped: `M N` is equivalent to `(M N)`.
|
|
|
|
* Applications are left-associative: `M N P` may be written instead of `((M N) P)`.
|
2020-11-02 15:59:35 -08:00
|
|
|
* The body of an abstraction or let expression extends as far right as possible: `\x. M N` means `\x.(M N)` and not `(\x. M) N`.
|
2019-08-21 15:18:25 -07:00
|
|
|
* A sequence of abstractions may be contracted: `\foo. \bar. \baz. N` may be abbreviated as `\foo bar baz. N`.
|
2020-11-03 11:33:35 -08:00
|
|
|
* Variables may be bound using let expressions: `let x = N in M` is syntactic sugar for `(\x. N) M`.
|
|
|
|
* Multiple variables may be defined in one let expression: `let x = N; y = O in M`
|
2021-03-05 23:38:21 -08:00
|
|
|
|
|
|
|
## Call/CC
|
|
|
|
This interpreter has preliminary support for
|
|
|
|
[the call-with-current-continuation control flow operator](https://en.wikipedia.org/wiki/Call-with-current-continuation).
|
|
|
|
However, it has not been thoroughly tested.
|
|
|
|
|
|
|
|
To use it, simply apply the variable `callcc` like you would a function, e.g. `(callcc (\k. ...))`.
|
|
|
|
|
|
|
|
Continuations are printed as `λ!. ... ! ...`, like a lambda abstraction
|
|
|
|
with an argument named `!` which is used exactly once;
|
|
|
|
however, continuations are *not* the same as lambda abstractions
|
|
|
|
because they perform the side effect of modifying the current continuation,
|
|
|
|
and this is *not* valid syntax you can input into the REPL.
|