# ITP Blatt 02

Besprechung: am 30.04.2026

```
{-# OPTIONS --allow-unsolved-metas #-}
open import Level using (Level)
open import Function.Base using (_∘_; id)
open import Relation.Binary.PropositionalEquality
```

## Implizite Allquantifizierung
Wenn man mehrere Funktionen schreiben möchte, die alle in
einer Variable all-quantifiziert sind, dann lässt sich das
so deklarieren:
```
private
  variable
    ℓ ℓ' ℓ'' : Level
    X : Set ℓ
    Y : Set ℓ'
    Z : Set ℓ''
```

## Reverse ∘ Reverse ≗ id
Da `reverse` in der Vorlesung leicht anders definiert ist als in der standard library,
wiederholen wir hier die Definitionen:
```
open import Data.List
open import Data.List.Properties using (++-identityʳ)

rev-acc : List X → List X → List X
rev-acc [] acc = acc
rev-acc (x ∷ xs) acc = rev-acc xs (x ∷ acc)

rev : List X → List X
rev xs = rev-acc xs []
```
Beweisen Sie, dass `reverse` zu sich selbst invers ist. Hierfür ist es nötig,
ein Hilfslemma für das um den Akkumulator verallgemeinerte `rev-acc` zu
beweisen. (Der Typ des Hilfslemmas ist unten im Abschnitt "Tipps")
```
rev∘rev≗id : ∀ {X : Set ℓ} → rev ∘ rev ≗ id {ℓ} {List X}
rev∘rev≗id xs =
  -- <LSG>
  trans (rev-acc∘rev-acc xs [] []) (++-identityʳ xs)
  where
    rev-acc∘rev-acc : ∀ (xs ys zs : List X) → rev-acc (rev-acc xs ys) zs ≡ rev-acc ys (xs ++ zs)
    rev-acc∘rev-acc [] ys zs = refl
    rev-acc∘rev-acc (x ∷ xs) ys zs =
      begin
      rev-acc (rev-acc xs (x ∷ ys)) zs ≡⟨ rev-acc∘rev-acc xs _ zs ⟩
      rev-acc (x ∷ ys) (xs ++ zs) ≡⟨⟩
      rev-acc ys ((x ∷ xs) ++ zs)
      ∎
      where open ≡-Reasoning
  -- </LSG>

```

## Binärdarstellung
Definieren Sie eine Funktion, die eine Binärzahl in eine natürlichen Zahl
umwandelt. Hierbei gibt es zwei Möglichkeiten, welche Binärziffern (Bits) am
Anfang der Liste stehen: die nieder- oder die höchstwertigsten Bits.
Definieren Sie beide Varianten:

(Tipp: Da die Operatoren `_+_` und `_*_` per Rekursion über das erste Argument
definiert sind, empfiehlt es sich, Konstanten nach links zu schreiben, also z.B.
`5 + (8 * x)`.)
```
open import Data.Bool
open import Data.Nat

--  Binärdarstellung "least-significant bit first"
lsb→nat : List Bool → ℕ
lsb→nat =
  -- <LSG>
  lsb→nat'
  where
    lsb→nat' : List Bool → ℕ
    lsb→nat' [] = 0
    lsb→nat' (true ∷ xs) = 1 + 2 * lsb→nat' xs
    lsb→nat' (false ∷ xs) = 2 * lsb→nat' xs
  -- </LSG>

-- Nach korrekter Definition können Sie zum Test folgenden
-- Code aktivieren:
-- <COMMENT>
_ : lsb→nat (true ∷ true ∷ false ∷ true ∷ []) ≡ 11
_ = refl
-- </COMMENT>

-- Definieren Sie zusätzlich die Umwandlung von Binärzahlen
-- in der Reihenfolge "most-significant bit first" zu natürlichen Zahlen
-- explizit mittels Akkumulator:
-- <LSG>
msb→nat' : ℕ → List Bool → ℕ
msb→nat' acc [] = acc
msb→nat' acc (false ∷ xs) = msb→nat' (2 * acc) xs
msb→nat' acc (true ∷ xs) = msb→nat' (1 + 2 * acc) xs
-- </LSG>

msb+acc→nat : ℕ → List Bool → ℕ
msb+acc→nat =
  -- <LSG>
  msb→nat'
  -- </LSG>

msb→nat : List Bool → ℕ
msb→nat = msb+acc→nat 0

-- Nach korrekter Definition können Sie zum Test folgenden
-- Code aktivieren:
-- <COMMENT>
_ : msb→nat (true ∷ false ∷ true ∷ true ∷ []) ≡ 11
_ = refl

_ : msb→nat (true ∷ true ∷ false ∷ true ∷ []) ≡ 13
_ = refl
-- </COMMENT>
```
Zeigen Sie, dass LSB und MSB gleichwertig sind; der Typ der Hilfsfunktion ist
unten in den "Tipps".
```
-- <LSG>
lsb≗msb∘rev' : ∀ (xs ys : List Bool) → lsb→nat (rev-acc xs ys) ≡ msb+acc→nat (lsb→nat ys) xs
lsb≗msb∘rev' [] ys = refl
lsb≗msb∘rev' (false ∷ xs) ys = begin
  lsb→nat (rev-acc (false ∷ xs) ys)  ≡⟨⟩
  lsb→nat (rev-acc xs (false ∷ ys))  ≡⟨ lsb≗msb∘rev' xs (false ∷ ys) ⟩
  msb+acc→nat (2 * lsb→nat ys) xs ≡⟨⟩
  msb+acc→nat (lsb→nat ys) (false ∷ xs)
  ∎
  where open ≡-Reasoning
lsb≗msb∘rev' (true ∷ xs) ys = lsb≗msb∘rev' xs (true ∷ ys)
-- </LSG>

lsb≗msb∘rev : ∀ (xs : List Bool) → lsb→nat (rev xs) ≡ msb→nat xs
lsb≗msb∘rev  xs =
    -- <LSG>
    lsb≗msb∘rev' xs []
    -- </LSG>
```

## Map erhält Komposition
Beweisen Sie, dass sich `map` mit Funktions-Komposition verträgt:
```
map-preserves-∘ : {g : Y → Z} {f : X → Y} → map (g ∘ f) ≗ map g ∘ map f
map-preserves-∘ {g = g} {f = f} =
  -- <LSG>
  helper
  where
    helper : ∀ x → map (g ∘ f) x ≡ map g (map f x)
    helper [] = refl
    helper (x ∷ xs) = cong ((g (f x)) ∷_) (helper xs)
  -- </LSG>
```


## Tipps
Typen der Hilfslemmatas:

* `∀ (xs ys zs : List X) → rev-acc (rev-acc xs ys) zs ≡ rev-acc ys (xs ++ zs)`
* `∀ (xs ys : List Bool) → lsb→nat (rev-acc xs ys) ≡ msb+acc→nat (lsb→nat ys) xs`

