Check out my first novel, midnight's simulacra!
Programming Language Theory: Difference between revisions
Line 51: | Line 51: | ||
** (λx. (f x)) →<sub>η</sub> f | ** (λx. (f x)) →<sub>η</sub> f | ||
==== | ====Numerics==== | ||
The integers (or any countably infinite set) can be represented via the [http://en.wikipedia.org/wiki/Church_encoding Church encoding] (or [http://en.wikipedia.org/wiki/Mogensen-Scott_encoding Mogensen-Scott], or others): | The integers (or any countably infinite set) can be represented via the [http://en.wikipedia.org/wiki/Church_encoding Church encoding] (or [http://en.wikipedia.org/wiki/Mogensen-Scott_encoding Mogensen-Scott], or others): | ||
* <tt>0 ≡ λf. λx. x</tt> | * <tt>0 ≡ λf. λx. x</tt> | ||
Line 58: | Line 58: | ||
* <tt>3 ≡ λf. λx. f (f (f x))</tt> | * <tt>3 ≡ λf. λx. f (f (f x))</tt> | ||
* <tt>n ≡ λf. λx. f<sup>n</sup>x</tt> | * <tt>n ≡ λf. λx. f<sup>n</sup>x</tt> | ||
Some basic arithmetic operations: | Some basic arithmetic operations: | ||
* <tt>plus ≡ λm. λn. λf. λx. m f (n f x)</tt> (from ''f<sup>(m + n)</sup>(x) = f<sup>m</sup>(f<sup>n</sup>(x))'') | * <tt>plus ≡ λm. λn. λf. λx. m f (n f x)</tt> (from ''f<sup>(m + n)</sup>(x) = f<sup>m</sup>(f<sup>n</sup>(x))'') | ||
Line 68: | Line 65: | ||
* <tt>pred ≡ λn. λf. λx. n (λg. λh. h (g f)) (λu. x) (λu. u)</tt> (returns 0 when applied to 0) | * <tt>pred ≡ λn. λf. λx. n (λg. λh. h (g f)) (λu. x) (λu. u)</tt> (returns 0 when applied to 0) | ||
* <tt>sub ≡ λm. λn. (n pred) m</tt> (using <tt>pred</tt> from above) | * <tt>sub ≡ λm. λn. (n pred) m</tt> (using <tt>pred</tt> from above) | ||
... | ====Logic==== | ||
The Church booleans take two arguments, and evaluate to one of them: | |||
* <tt>true ≡ λa. λb . a</tt> | |||
* <tt>false ≡ λa. λb . b</tt> | |||
Using them, we implement basic conditional logic: | |||
* <tt>if[A, B, C] ≡ A B C</tt> (use <tt>true</tt>/<tt>false</tt> for A. Evaluates to B on <tt>true</tt>, C on <tt>false</tt>) | * <tt>if[A, B, C] ≡ A B C</tt> (use <tt>true</tt>/<tt>false</tt> for A. Evaluates to B on <tt>true</tt>, C on <tt>false</tt>) | ||
* <tt>not ≡ λt. t false true</tt> (β-equivalent to <tt>if[A, false, true]</tt>) | * <tt>not ≡ λt. t false true</tt> (β-equivalent to <tt>if[A, false, true]</tt>) |
Revision as of 07:48, 7 December 2009
The Church-Turing thesis equates a vaguely-defined set of "computable" functions with the partial recursive functions. Several systems are only as powerful as the partial recursives (Turing-complete): Turing machines and the λ-calculus are two. Programming languages provide further syntaxes and semantics, but all you really need in life is combinatory logic.
Applicative/Functional Programming
Expressions compose functions rather than values. Backus proposed three tiers of complexity in his Turing Award lecture:
- Simply functional language (fp): No state, limited names, finitely many functional forms, simple substitution semantics, algebraic laws
- Formal functional system (ffp): Extensible functional forms, functions represented by objects, translation of object representation to applicable form, formal semantics
- Applicative state transition system (ast): ffp plus mutable state and coarse-grained operations thereupon
Higher-order functions map one or more functions to a function.
Combinatory Logic
SKI Calculus
- I ≡ λx. x
- K ≡ λx, y. x
- S ≡ λx, y, z. (x z (y z))
Fixed-Point Combinators
Higher-order functions which compute the fixed points of their inputs. Curry's Y-combinator was the first:
- Y ≡ λf. (λx. f (x x)) (λx. f (x x)) (untyped λ-calculus)
- Y ≡ S (K (S I I)) (S (S (K S) K) (K (S I I))) (SKI calculus)
Divergence-free evaluation of the Y-combinator requires call-by-name semantics. Call-by-value semantics can make use of the Θv (Turing) or Z-combinators:
- Θv ≡ (λx. λy. (y (λz. x x y z))) (λx. λy. (y (λz. x x y z)))
- Z ≡ λf. (λx. f (λy. x x y)) (λx. f (λy. x x y)) (via η-expansion on Y)
The infinitely many fixed-point combinators of untyped λ-calculus are recursively enumerable.
Untyped λ-calculus
Two operators (function definition and application) upon one operand type (λ-expression).
- Function definition: (λboundparam. body)
- Function application: function(actualparam)
The body is made up of free and bound variables. Those not present in the λ's list of bound variables are free. A λ-expression with no free variables is closed (closed expressions are equivalent in power to combinatory logic). A λ-expression enclosed in scopes of its free variables is meaningful.
Grammar
λ-term ::= λ-app | λ-abst | var λ-app ::= λ-term λ-term λ-abst ::= 'λ'var'.' λ-term
This abstract grammar can be augmented with associativity rules and grouping syntax (parentheses) to provide a concrete grammar. If verbosity is no issue, no associativity rules need be specified for the following grammar:
λ-term ::= λ-app | λ-abst | var λ-app ::= '(' λ-term λ-term ')' λ-abst ::= '(' 'λ'var'.' λ-term ')'
Evaluation
We'll use a substitution syntax to rewrite λ-calculus strings. {N / X}M substitutes expression N for free instances of X in expression M:
- If M is a variable ({N / X}V), replace M with X if and only if M is N.
- If M is a λ-app ({N / X}(A B)), {N / X}M = (({N / X}A) ({N / X}B))
- Otherwise, M is a λ-abst ({N / X}(λV. B)).
- If X is V, M is unchanged (X is bound in M).
- If X does not appear in B, M is unchanged (no free X in M)
- If V occurs free in N, substitute N for X throughout B.
- Otherwise, the substitution in this form is invalid (but it can be made valid...)
With this syntax, we define evaluation rules. Application of the a rule preserves its equivalence:
- ɑ-conversion renames bound variables with any variable y which is not free, preserving ɑ-equivalence:
- λx. m →ɑ λy. {y / x}m
- β-reduction replaces a formal parameter with an actual parameter, preserving β-equivalence:
- (λx. m) n →β {n / x}m
- η-reduction eliminates bindings unused within a scope, preserving η-equivalence:
- (λx. (f x)) →η f
Numerics
The integers (or any countably infinite set) can be represented via the Church encoding (or Mogensen-Scott, or others):
- 0 ≡ λf. λx. x
- 1 ≡ λf. λx. f x
- 2 ≡ λf. λx. f (f x)
- 3 ≡ λf. λx. f (f (f x))
- n ≡ λf. λx. fnx
Some basic arithmetic operations:
- plus ≡ λm. λn. λf. λx. m f (n f x) (from f(m + n)(x) = fm(fn(x)))
- succ ≡ λn. λf. λx. f (n f x) (β-equivalent to (plus 1) for our 1 from above)
- mult ≡ λm. λn. λf. n (m f) (from f(m * n) = (fm)n)
- pow ≡ λm. λn. n m
- pred ≡ λn. λf. λx. n (λg. λh. h (g f)) (λu. x) (λu. u) (returns 0 when applied to 0)
- sub ≡ λm. λn. (n pred) m (using pred from above)
Logic
The Church booleans take two arguments, and evaluate to one of them:
- true ≡ λa. λb . a
- false ≡ λa. λb . b
Using them, we implement basic conditional logic:
- if[A, B, C] ≡ A B C (use true/false for A. Evaluates to B on true, C on false)
- not ≡ λt. t false true (β-equivalent to if[A, false, true])
Syntactic sugar
- Left-associative application as implicit parentheses
- Use of definitions (allowing identifiers to stand in as λ-expressions)
- Currying: (λx, y. x + y) rather than (λx. (λy. x + y))
- Numeric literals rather than Church encoding