SK Combinators
The SK combinator calculus is a turing-complete system of computation / logic without variables or scopes. SK programs are composed of two "combinators": \(S\) and \(K\). The semantics of \(S\) and \(K\) are given by:
$$ K x y = x \\ S x y z = x z (y z) $$
The \(K\) combinator can be thought of as a "constant function maker." In lambda calculus, the \(K\) combinator is defined as:
$$ (\lambda a.(\lambda b.a)) $$
The \(S\) combinator can be thought of as a substitution function. It copies the argument \(z\), applies it to \(x\) and \(y\), then applies th results to each other.
The SK combinator calculus has been demonstrated to be turing-complete, and equivalent to the lambda calculus.
Lean Examples
We can encode the combinators as dependent functions in Lean:
import Mathlib.Tactic
def K {α : Type} {β : Type} (x : α) (_y : β) := x
def S {α : Type} {β : Type} {γ : Type} (x : α → β → γ) (y : α → β) (z : α) := x z (y z)
#eval K 0 1
-- => 0
#eval S (λx y => x + y) Nat.succ 1
-- => 3
The SK combinators are turing complete. Dynamic evaluation of the combinators in a dependently typed language will invoke unfounded recursion, similarly to in the lambda calculus.
Strong normalization of the typed SK combinators has been comparatively under-studied compared to the simply typed lambda calculus. Furthermore, proofs of strong normalization of the dependently-typed SK combinators have yet to be mechanized in a language like Lean.
In this paper, I detail my interpretation of the combinators as dependently-typed functions, my representation of them in Lean, and my proof of their strong normalization in Lean.
Made by Dowland Aiello.