###### tags: `MP`
# MP wykład 2 (II tercja)
## Co wcześciej:
1. Indukcja strukturalna => względem jakiejś struktury do:
- dowodzenia poprawności programów
- uczyliśmy się żeby pisać czytelny, zrozumiały kod???
## Listy
Wcześniej robiliśmy:
```plait!
(define (my-map f xs)
(if (empty? xs) empty
(cons (f first xs) (my-map f (rest xs)))))
```
Problem jest taki, że taki program jest narażony na dużo błędów a system typów nie pomoże (jeśli się zapętlimy to i tak zostanie otypowana). Można zrobić:
```plait!
(define (my-map f xs)
(type-case (Listof 'a) xs
[empty empty]
[(cons x xs) (cons (f x) (my-map f xs))]))
```
To daje nam:
1. czytelniejszy kod
2. łatwiejsze unikanie błędów
Jak mamy dwie zmienne o tej samej nazwie, to nie możemy się odwołać do starej wartości, więc nie jesteśmy w stanie przypadkiem się zapętlić.
W type-case:
1. kolejność nie ma znaczenia (w plaicie)
2. jak zapomnimy o jakimś to jest zgłaszany błąd
W trzeciej tercji to nam się przyda, np. gdy będziemy chcieli dodać nową rzecz do naszego języka programowania, bo plait nam powie gdzie trzeba ten przypadek rozważyć.
W Lispie programy to lista, w której mogą być pozagnieżdżane inne listy, dlatego są te wszystkie nawiasy i generalnie racket i plait wyglądają jak wyglądają.
```plait
(define-type (Tree 'a)
(leaf)
(node [l : (Tree 'a)] [elem: 'a] [r : (Tree 'a)]))
(define (insert x t)
(type-case (Tree 'a) t
[(leaf) (node (leaf) x (leaf))]
[(node l y r)
(if < x y)
(node (insert x l) y r)
(node l y (insert x r))]))
```
Jak to by wyglądało w Rackecie?
```racket
(struct leaf () #:transparent)
(struct node (l elem r) #:transparent)
(define (insert x t)
(match t
[(leaf) (node (leaf) x (leaf))]
[(node l y r)
(if < x y)
(node (insert x l) y r)
(node l y (insert x r))]))
```
Tutaj te l, y, r mogą być np parametrami wzorców, np. zamiast l może być (leaf), oczywiście tylko w Rackecie.
## Zaimplementujmy kolejki
```plait
(define-type (Queue 'a)
(queue (f : Listof 'a) (r : Listof 'a)))
(define (queue-empty)
(queue empty empty))
(define (push q x)
(type-case (Queue 'a) q
[(queue f r) (queue f (cons x r))]))
(define (pop q)
(type-case (Queue 'a) q
[(queue f r) ...]))
(define (is-empty? q)
(type-case (Queue 'a) q
[(queue f r) (null? f)] ;mamy niezmiennik że f jest puste
;tylko gdy cała lista jest pusta
...
```
Tutaj bawimy się i generalnie robimy to samo co robiliśmy na zadaniu takim samym na liście.
### Jak można to poprawić?
```plait
(define-type (Queue 'a)
(empty-queue)
(queue (f : ('a * Listof 'a)) (r : (a' * Listof 'a))))
```
Albo lepiej:
```plait
(define-type (Queue 'a)
(empty-queue)
(queue (h : 'a ) (f : Listof 'a) (r : Listof 'a)))
```
Przerobiliśmy kod, coś to dało, ale "być może nie było to potrzebne". Udało się wyrazić niezmiennik w typach, więc mamy pewność, że będzie zachowany. Wada jest taka, że kod jest znacznie dłuższy.
#### Na 3 godzinie nie byłam