ExamplesBy LevelBy TopicLearning Paths
234 Expert

Propositions as Types

Functional Programming

Tutorial Video

Text description (accessibility)

This video demonstrates the "Propositions as Types" functional Rust example. Difficulty level: Expert. Key concepts covered: Functional Programming. Extending the Curry-Howard correspondence, this example makes the type-as-proposition correspondence concrete with examples: conjunction (product types), disjunction (sum types), implication (function types), negation (function to `!`), and the universal and existential quantifiers (generic types and existential types). Key difference from OCaml: 1. **Existentials**: Rust's `Box<dyn Trait>` is a runtime existential; OCaml's first

Tutorial

The Problem

Extending the Curry-Howard correspondence, this example makes the type-as-proposition correspondence concrete with examples: conjunction (product types), disjunction (sum types), implication (function types), negation (function to !), and the universal and existential quantifiers (generic types and existential types). Seeing familiar type operations through the logical lens reveals why type system design and formal logic are the same discipline.

🎯 Learning Outcomes

  • • See conjunction, disjunction, implication, and negation as concrete Rust types
  • • Understand universal quantification as generic type parameters: ∀T. P(T) = fn<T>(...)
  • • Understand existential quantification as Box<dyn Trait> or impl Trait
  • • Connect these to everyday programming: Option = "maybe A", Result = "A or E"
  • Code Example

    #![allow(clippy::all)]
    // Stub — awaiting conversion from OCaml source.

    Key Differences

  • Existentials: Rust's Box<dyn Trait> is a runtime existential; OCaml's first-class modules and GADTs provide more expressive existentials.
  • Universal quantification: Rust's generics are explicit (fn<T>); OCaml's polymorphism is implicit (inferred by type inference) — both express ∀T.
  • Negation: Both use a function to an uninhabited type; Rust's ! is built-in, OCaml uses type void = |.
  • Proof relevance: Rust and OCaml are "proof-relevant" (the computation matters); systems like Coq are proof-irrelevant (only inhabitation matters).
  • OCaml Approach

    OCaml's type algebra mirrors this directly. The type nonrec keyword and abstract types provide the tools. Coq (the proof assistant) was originally designed with OCaml-like syntax specifically because of the Curry-Howard correspondence — proof terms in Coq are OCaml-like programs.

    Full Source

    #![allow(clippy::all)]
    // Stub — awaiting conversion from OCaml source.

    Deep Comparison

    OCaml vs Rust: Propositions Types

    Overview

    See the example.rs and example.ml files for detailed implementations.

    Key Differences

    AspectOCamlRust
    Type systemHindley-MilnerOwnership + traits
    MemoryGCZero-cost abstractions
    MutabilityExplicit refmut keyword
    Error handlingOption/ResultResult<T, E>

    See README.md for detailed comparison.

    Exercises

  • Write double_negation_intro<A>(a: A) -> impl Fn(impl Fn(A) -> !) -> ! as a type-level proof.
  • Implement De Morgan: (A -> !) -> (B -> !) -> Either<A, B> -> ! — De Morgan's law as a Rust function.
  • Show why fn<A>(f: impl Fn(A) -> A) -> A is uninhabitable (no value of any type can be returned without an A to start with).
  • Open Source Repos