Skip to content

Instantly share code, notes, and snippets.

@hirrolot
hirrolot / stlc.ml
Last active October 1, 2024 17:10
A two-line lambda calculus with metacircular (shallow) embedding
let lam f = f
let appl f x = f x
@hirrolot
hirrolot / stlc-form-meaning-hoas.ml
Last active October 1, 2024 17:10
A simply typed lambda calculus in tagless-final (HOAS)
module type Form = sig
type 'a meaning
val lam : ('a meaning -> 'b meaning) -> ('a -> 'b) meaning
val appl : ('a -> 'b) meaning -> 'a meaning -> 'b meaning
end
(* Evaluate a given term. *)
module Eval = struct
type 'a meaning = 'a
@hirrolot
hirrolot / stlc-form-meaning-de-bruijn.ml
Last active December 18, 2024 02:10
A simply typed lambda calculus in tagless-final (De Bruijn indices)
module type Form = sig
type ('env, 'a) meaning
val vz : ('a * 'env, 'a) meaning
val vs : ('env, 'a) meaning -> ('b * 'env, 'a) meaning
val lam : ('a * 'env, 'b) meaning -> ('env, 'a -> 'b) meaning
val appl :
('env, 'a -> 'b) meaning -> ('env, 'a) meaning -> ('env, 'b) meaning
end
@hirrolot
hirrolot / untyped-hoas.ml
Last active October 1, 2024 17:08
Untyped lambda calculus with HOAS and De Bruijn levels
type term = Lam of (term -> term) | Appl of term * term | FreeVar of int
let unfurl lvl f = f (FreeVar lvl)
let unfurl2 lvl (f, g) = (unfurl lvl f, unfurl lvl g)
let rec print lvl =
let plunge f = print (lvl + 1) (unfurl lvl f) in
function
| Lam f -> "(λ" ^ plunge f ^ ")"
| Appl (m, n) -> "(" ^ print lvl m ^ " " ^ print lvl n ^ ")"
@hirrolot
hirrolot / CoC.ml
Last active July 25, 2026 23:38
How to implement dependent types in 80 lines of code
type term =
| Lam of (term -> term)
| Pi of term * (term -> term)
| Appl of term * term
| Ann of term * term
| FreeVar of int
| Star
| Box
let unfurl lvl f = f (FreeVar lvl)
@AndrasKovacs
AndrasKovacs / HOASOnly.hs
Last active April 11, 2025 20:56
HOAS-only lambda calculus
{-# language BlockArguments, LambdaCase, Strict, UnicodeSyntax #-}
{-|
Minimal dependent lambda caluclus with:
- HOAS-only representation
- Lossless printing
- Bidirectional checking
- Efficient evaluation & conversion checking
Inspired by https://gist.github.com/Hirrolot/27e6b02a051df333811a23b97c375196
@gabriel-fallen
gabriel-fallen / adts.lean
Created February 26, 2023 15:35
Correct-by-construction solutions to the Wolf-Goat-Cabbage game
namespace ADTs
/-
In the game we have two banks of a river: left and right,
and four characters: a wolf, a goat, a cabbage, and a farmer.
The farmer prevents abybody from eathing anything, otherweise
the wolf eats the goat, or the goat eats the cabbage.
The game starts with all the characters on the left bank and
the goal is to move everyone to the right bank safe and sound.
The farmer can carry a single other character at a time
@hirrolot
hirrolot / a-main.ml
Last active October 26, 2025 01:02
A simple CPS conversion as in "Compiling with Continuations", Andrew W. Appel
(* A variable identifier of the lambda language [term]. *)
type var = string [@@deriving eq]
(* The lambda language; direct style. *)
type term =
| Var of var
| Fix of (var * var list * term) list * term
| Appl of term * term list
| Record of term list
| Select of term * int
@hirrolot
hirrolot / cps-eval.ml
Last active March 13, 2026 09:45
A simple CPS evaluation as in "Compiling with Continuations", Andrew W. Appel
type cps_var =
(* Taken from the lambda term during CPS conversion. *)
| CLamVar of string
(* Generated uniquely during CPS conversion. *)
| CGenVar of int
type cps_term =
| CFix of (cps_var * cps_var list * cps_term) list * cps_term
| CAppl of cps_var * cps_var list
| CRecord of cps_var list * binder
@hirrolot
hirrolot / a-preface.md
Last active December 27, 2025 08:17
Higher-order polymorphic lambda calculus (Fω)

This is a minimalistic OCaml implementation of the type system from chapter 30 of TAPL, "Higher-Order Polymorphism".

The implementation uses bidirectional typing and does not feature existential types. Binders are represented as metalanguage functions (HOAS-style), whereas free variables (TyFreeVar and FreeVar in the code) are represented as De Bruijn levels indicating a distance from the root.

See also: