A purely-functional programming language with Hindley-Milner type inference and `callcc`.
Go to file
James T. Martin 25658f370a
Complexity was getting out of hand. Beginning a rewrite. Added tests.
2019-12-11 18:29:28 -08:00
app Complexity was getting out of hand. Beginning a rewrite. Added tests. 2019-12-11 18:29:28 -08:00
src/LambdaCalculus Complexity was getting out of hand. Beginning a rewrite. Added tests. 2019-12-11 18:29:28 -08:00
test Complexity was getting out of hand. Beginning a rewrite. Added tests. 2019-12-11 18:29:28 -08:00
.gitignore Complexity was getting out of hand. Beginning a rewrite. Added tests. 2019-12-11 18:29:28 -08:00
LICENSE Initial commit. Some terms are still not evaluated correctly. 2019-08-15 10:42:24 -07:00
README.md Massive refactoring. This project is no longer "just an exercise". 2019-08-29 20:46:42 -07:00
Setup.hs Initial commit. Some terms are still not evaluated correctly. 2019-08-15 10:42:24 -07:00
package.yaml Complexity was getting out of hand. Beginning a rewrite. Added tests. 2019-12-11 18:29:28 -08:00
stack.yaml Complexity was getting out of hand. Beginning a rewrite. Added tests. 2019-12-11 18:29:28 -08:00
stack.yaml.lock Complexity was getting out of hand. Beginning a rewrite. Added tests. 2019-12-11 18:29:28 -08:00

README.md

James Martin's Lambda Calculus

An implementation of various type systems and evaluation strategies for the lambda calculus.

This project is a work-in-progress, and currently lacks many essential features that would be necessary to be a useful programming language.

Usage

Type in your expression at the prompt: >> . The result of the evaluation of that expression will then be printed out. Exit the prompt with Ctrl-C (or however else you kill a program in your terminal).

Bound variables will be printed followed by a number representing the number of binders between it and its definition for disambiguation.

Example session

>> let D = (\x. x x) in let F = (\f. f (f y)) in D (F ())
y y
>> let T = (\f x. f (f x)) in (\f x. T (T (T (T T))) f x) () y
y
>> \x. \y. y x
\x. \y. y:0 x:1
>> ^C

Notation

Conventional Lambda Calculus notation applies, with the exception that variable names are mmultiple characters long, and \ is used in lieu of λ for convenience.

  • 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).
  • The body of an abstraction extends as far right as possible: \x. M N means \x.(M N) and not ``(\x. M) N`.
  • A sequence of abstractions may be contracted: \foo. \bar. \baz. N may be abbreviated as \foo bar baz. N.
  • Variables may be bound using let expressions: let x = N in M abbreviates (\x. N) M.

Violations of convention

  • I use spaces to separate variables in abstractions instead of commas because I think it looks better.

Additional extensions to notation

Since \x. x is the left identity of applications and application syntax is left-associative, I (syntactically) permit unary and nullary applications so that () is \x. x, and (x) is x.

On the same principle, the syntax of a lambda of no variables \. e is e.

Roadmap

Complete

  • Type systems:
    • Untyped
  • Representations:
    • The syntax tree
    • Reverse de Bruijn
  • Syntax:
    • Basic syntax
    • Let expressions
  • Evaluation strategies:
    • Lazy (call-by-name to normal form)

In-progress

  • Type systems:
    • Simply typed
  • Representations:
    • De Bruijn

Planned

My ultimate goal is to develop this into a programming language that would at least theoretically be practically useful. I intend to do a lot more than this in the long run, but it's far enough off that I haven't nailed down the specifics yet.

  • Built-ins:
    • Integers
  • Type systems:
    • Hindley-Milner
    • System F
  • Representations:
    • A more conservative syntax tree that would allow for better error messages
  • Evaluation strategies:
    • Complete laziness
    • Optimal
  • Syntax:
    • Top-level definitions
    • Type annotations
    • let*, letrec
    • More syntax (parsing and printing) options:
      • Also allow warnings instead of errors on disabled syntax.
        • Or set a preferred printing style without warnings.
        • Or print in an entirely different syntax than the input!
      • Disable empty application: () no longer parses (as \x. x).
        • Forbid single-term application: (x) no longer parses as x.
      • Disable empty variable-list: λ. x no longer parses (as just x).
      • Disable block arguments: f λx. x is no longer permitted; f (λx. x) must be used instead.
        • Except for at the top level, where an unclosed lambda is always permitted.
      • Configurable variable-list syntax:
        • Mathematics style: One-letter variable names, no variable separators.
        • Computer science style: Variable names separated by commas instead of spaces.
      • Configurable λ syntax: any one of λ, \, or ^, as I've seen all three in use.
        • Currently, either λ or \ is permitted, and it is impossible to disable either.
      • Disable let expressions.
      • Disable syntactic sugar entirely (never drop parentheses).
      • Pedantic mode: forbid using more parentheses than necessary.
      • Pedantic whitespace (e.g. forbid ( a b c)).
    • Pretty-printing mode.
    • Indentation-based syntax.
  • Features:
    • A better REPL (e.g. the ability to edit the line buffer)
    • The ability to import external files
    • The ability to choose the type system or evaluation strategy
    • Better error messages for parsing and typechecking
    • Reduction stepping