Intro

{-# OPTIONS --allow-unsolved-metas --without-K #-}

Curry-Howard-Korrespondenz

Beweis-Regeln und Regeln von Typsystemen stehen in Korrespondenz zueinander:

Logik Programme
vgl. GLoIn vgl. ThProg
Logische Formeln A ∧ B → A Typen von Programmen A × B → A
Beweise Γ ⊢ A ∧ B → A Typisierung: Γ ⊢ (λ p. p λ x y. x) : A × B → A
Implikation A → B Funktionstyp A → B
Konjunktion A ∧ B Produkt-Typ A × B
Disjunktion A ∨ B Union-Typ A + B
Allquantor ∀x.φ(x) Polymorphismus ∀ x.φ(x)

⇒ Wir beweisen mathematische Aussagen, indem wir Programme mit dem passenden Typ konstruieren.

Syntax

  • Haskell-artig
  • Identifier: UTF-8-Zeichenkennten getrennt durch Leerzeichen und .;{}()@"

Funktionstypen

Agda ist dependently-typed, das bedeutet, dass Typen von Werten abhängen können. Da 'Set' ist selbst ein Typ, lässt sich damit Polymorphismus, implementieren:

id :  (S : Set)  S  S
id S x = x

Hier ist S ein Wert vom Typ Set.

id' :  (S : Set)  (S  S)
id' = λ S  λ x  x

Der Funktionstyp S → S selbst liegt auch in Set:

Endofunction : Set  Set
Endofunction S = S  S
-- Definition mittels Endofunction:
id₂ :  (S : Set)  Endofunction S
id₂ S x = x

Holes

Statt von oben nach unten schreibt man Agda-Programme von außen nach innen:

id₃ :  (S : Set)  Endofunction S
id₃ S x = x -- Ersetzen Sie x durch ? um ein Hole zu erzeugen

Operatoren

_∨_ : Set  Set  Set₁
A  B =  (C : Set)  (A  C)  (B  C)  C

_∧_ : Set  Set  Set₁
A  B =  (C : Set)  (A  B  C)  C
  • Funktion X -> Y und X und Y auf level ℓ, dann ist (X → Y) auch auf Level ℓ
  • Funktion X -> Y bedeutet: ∀ (x : X) → Y
  • Parameter C ist vom Typ Set
  • => Set → Set ∈ Set₁

Modules

module Logic-Examples (A : Set) (B : Set) where
  ∨-comm : (A  B)  (B  A)
  ∨-comm A∨B C B→C A→C = A∨B C A→C B→C

Datentypen

data  : Set where
  zero : 
  suc :   


_+_ :     
zero + b = b
suc a + b = suc (a + b)

open import Data.Bool using (Bool; true; false)

_≡?_ :     Bool
zero ≡? zero      = true
zero ≡? suc b     = false 
suc a ≡? zero     = false
suc a ≡? suc b    = a ≡? b

data _≡_ {} {X : Set } : X  X  Set  where
  refl :  (x : X)  x  x

infix 4 _≡_

zero+a≡a :  (a : )  zero + a  a
zero+a≡a a = refl a
Ende der Vorlesung am 13. April 2026

Implizite Argumente

  • Funktionsargumente können weggelassen werden, wenn sich diese durch die Unifikation automatisch ergeben.
  • Syntax:
  • {…} um in der Funktionsdefinition ein Argument als implizit zu markieren
  • _ um beim Funktionsaufruf ein explizites Argument von Agda finden zu lassen.
-- Funktionen erhalten Gleichheit:
cong :  {a b : }  (f :   )  a  b  f a  f b
cong f (refl a) = refl (f a)

-- Wenn wir cong aufurufen, dann ergeben sich die Werte für
-- a und b automatisch aus `a ≡ b`
a+zero≡a :  (a : )  a + zero  a
a+zero≡a zero = refl zero
a+zero≡a (suc a) =
  cong {a + zero} {a} suc (a+zero≡a a)
  -- identisch zu: cong {a + zero} {a} suc (a+zero≡a a)

Weiteres Beispiel: Implizite Grundmenge bei _≡_ oben. In der stdlib ist der Parameter an refl implizit, da er sich meist aus dem Kontext ergibt, wie z. B. in der Definition von sym:

sym :  {X : Set} {a : X} {b}  a  b  b  a
sym (refl _) = refl _
--        ^         ^--- Agda leitet den Parameter aus dem Kontext ab
--        '----  Der Wert bekommt keinen Namen, steht aber trotzdem zur Verfügung:
--               a : ℕ   (not in scope)

trans :  {X : Set} {a b c : X}  a  b  b  c  a  c
trans (refl x) eq = eq

+-suc :  a b  suc (a + b)  (a + suc b)
+-suc zero b = refl (suc b)
+-suc (suc a) b = cong suc (+-suc a b)

+-comm₀ :  a b  a + b  b + a
+-comm₀ zero b = sym (a+zero≡a b)
+-comm₀ (suc a) b = trans (cong suc IH) (+-suc b a)
  where
    IH = +-comm₀ a b


subst :  {a b : }  (P :   Set)  a  b  P a  P b
subst P (refl a) = id (P a)

+-comm :  a b  _≡_ (a + b) (b + a)
+-comm zero b = sym (a+zero≡a b)
+-comm (suc a) b = trans (cong suc (+-comm a b)) (+-suc b a)

Gleichungsketten

_∎ :  {X : Set} (n : X)  n  n
_∎ = refl
infix 3 _∎

_≡⟨_⟩_ :  {X : Set} n {m}  n  m  { : X}  m    n  
n ≡⟨ n≡m  m≡ℓ = trans n≡m m≡ℓ 
infixr 2 _≡⟨_⟩_

+-comm' :  a b  _≡_ (a + b) (b + a)
+-comm' zero b = sym (a+zero≡a b)
+-comm' (suc a) b =
        (suc a + b) ≡⟨ cong suc (+-comm' a b) 
        suc (b + a) ≡⟨ +-suc b a 
        (b + suc a) 

Warnung: die Gleichungsketten in der stdlib beginnen mit begin_

Entscheidungsprozeduren

  • Einbettung Bool ↪ Set
  • Korrektheitsbeweis von _≡?_
  • Dot-Pattern
-- import Data.Empty
data  : Set where

-- import Data.Unit
data  : Set where
  tt : 

Truth : Bool  Set
Truth false = 
Truth true = 

≡?-⇐ :  a b  a  b  Truth (a ≡? b)
≡?-⇐ zero a (refl a) = tt
≡?-⇐ (suc a) (suc a) (refl (suc a)) = ≡?-⇐ a a (refl _)
Ende der Vorlesung am 16. April 2026

In ≡?-⇐ nutzen wir das Prinzip des "Fordings".

Rückrichtung:

≡?-⇒ :  a b  Truth (a ≡? b)  a  b
≡?-⇒ zero zero t = refl _
≡?-⇒ zero (suc b) ()   -- hier kein '=', () ≡ "unmögliches pattern"
≡?-⇒ (suc a) (suc b) t = cong suc (≡?-⇒ a b t)

Level

import Level as L
open import Level using (Level)

weak-initial : { : Level} (X : Set )  Set (L.suc )
weak-initial {} X =  (Y : Set )  (X  Y)

Funktionen

_∘_ :  {ℓ₁ ℓ₂ ℓ₃} {X : Set ℓ₁} {Y : Set ℓ₂} {Z : Set ℓ₃} 
        (Y  Z)  (X  Y)  (X  Z)
(g  f) x = g (f x)

∘-assoc :  {ℓ₁ ℓ₂ ℓ₃ ℓ₄} {W : Set ℓ₁} {X : Set ℓ₂} {Y : Set ℓ₃} {Z : Set ℓ₄}
          (f : W  X) (g : X  Y) (h : Y  Z)  h  (g  f)  (h  g)  f
∘-assoc f g h = refl _

Records

module Non-Dependent-Product where

Das übliche Produkt ist ein record:

  record _×_ { ℓ' : Level} (X : Set ) (Y : Set ℓ') : Set ( L.⊔ ℓ') where
    constructor _,_
    field
      fst : X
      snd : Y

  module ×-properties { ℓ' : Level} (X : Set ) (Y : Set ℓ') where
    swap : X × Y  Y × X
    swap (x , y) = y , x

    swap' : X × Y  Y × X
    swap' p =
      record
      { fst = p.snd
      ; snd = p.fst
      }
      where
        module p = _×_ p

Dependent-Product:

record Σ { ℓ' : Level} (X : Set ) (P : X  Set ℓ') : Set ( L.⊔ ℓ') where
  constructor _,_
  field
    fst : X
    snd : P fst

syntax Σ A  x  B) = Σ[ x  A ] B

_×_ : { ℓ' : Level} (X : Set ) (Y : Set ℓ')
       Set ( Level.⊔ ℓ')
X × Y = Σ X  x  Y)

 : { ℓ' : Level} {X : Set } (P : X  Set ℓ')  Set ( L.⊔ ℓ')
 = Σ _
syntax   x  B) = ∃[ x ] B

Currying des Dependent-Products = Dependent Functions:

module Dependent-Currying (X : Set) (P : X  Set) (Y : Set) where
  curry : (Σ[ x  X ] (P x)  Y)  (∀ (x : X)  P x  Y)
  curry f x Px = f (x , Px)

  uncurry : (∀ (x : X)  P x  Y)  (Σ[ x  X ] (P x)  Y)
  uncurry f (x , Px) = f x Px

  _⇔_ : Set  Set  Set
  X  Y = (X  Y) × (Y  X)

  [un]curry : (∀ (x : X)  P x  Y)  (∃[ x ] (P x)  Y)
  [un]curry = uncurry , curry

  uncurry∘curry≡id : uncurry  curry  id _
  uncurry∘curry≡id = refl (uncurry  curry)

  curry∘uncurry≡id : curry  uncurry  id (∀ (x : X)  P x  Y)
  curry∘uncurry≡id = refl _

Funktionen

Die Relation f ≐ g beschreibt, dass die Funktionen f und g Punktweise identisch sind:

_≐_ :  {ℓ₁ ℓ₂} {X : Set ℓ₁} {Y : Set ℓ₂} (f g : X  Y)  Set (ℓ₁ L.⊔ ℓ₂)
f  g =  x  f x  g x

Stdlib

import Function.Base using (_∘_) -- ∘ allows composition of dependent functions

Agda Quellcode herunterladen