###### tags: `MP`
# Wykład III
## Fragment do wykładu I tej tercji
Wcześniej przy języku dotyczącym operacji arytmetycznych mieliśmy tak, że wyjątki zwracaliśmy "krokowo". Jak mamy interpreter w postaci maszyny abstrakcyjnej to ten interpreter był ogonowy, a nie zagnieżdzony, jak to było wcześniej.
Ogonowy => wywołanie dalsze jest ostatnią rzeczą, którą robimy => jak napotkamy błąd to możemy od razu powiedzieć, że wynikiem działania całego programu jest błąd (wyrzucamy stos i kończymy działanie zwracając błąd), a nie, że musimy propagować błąd jak poprzednio
## Zejście poziom niżej z reprezentacją funkcji
Ostatnio: funkcje na poziomie interpretera były reprezentowane przez funkcje (Value -> Value).
**Jak miałaby wyglądać struktura danych (pierwszorzędowa + funkcja interpretująca) reprezentująca wszystko, co ta funkcja robi?**
Jak do tej pory wyglądało:
```plait
{lambda {x} e} env
(funV (lambda (v) (eval e (extend-env env x v))))
```
Chcemy to zareprezentować trójką [x, e, env]. Wtedy musimy zmienić apply:
```plait
(define (apply [v1 : Value] [v2 : Value]) : Value
(type-case Value v1
[(funV x b env)
(eval b (extend-env env x v2))]
[else ERROR]))
```
To jest już znacznie bliższe reprezentacji niskopoziomowej.
Te dwa interpretery mogłyby być równoważne, ale pokazanie tego nie jest proste (gdy damy to policzenia funkcję w pierwszym przypadku dostaniemy funkcję a w drugim strukturę z jakimiś danymi). Pokazanie równoważności by wymagało opisania kiedy struktura (domknięcie) jest równoważne.
**Ważne:** jeśli nie zadbamy o to, żeby wziąć odpowiednie środowisko, bo inaczej będzie dynamiczne typowanie zmiennych, i wynik funkcji zależy nie tylko od jej argumentów ale też momentu wywołania. Działają tak niektóre starsze dialekty Lispu, ponieważ na początku popełniono ten błąd i w tych dialektach to nadal zostało.
## Jak napisać silnię?
Jak mamy `define` albo `letrec` to nie ma problemu. Czy umiemy napisać silnię bez tego? (rekursja bez rekursji)
Użyjemy tych fanych aplikowanych do samych siebie lambd.
```racket
(define (silnia n)
(let ([fact
(λ (f) (λ (n) (if (= n 0)
1
(* n ((f f) (- n 1))))))])
((fact fact) n)))
```
Oczywiście zamiast define możemy użyć let, bo już w define nie korzystamy z rekursji.
## Nieskończona pętla:
```plait
(let ([w (lambda (x) (x x))])
(w w))
```
Samo w sobie nie jest użyteczne, ale można wykorzystać to.
## Operator punktu stałego
Chcemy mieć taką funkcję `fix`, żeby `(fix f)` $\to$ `(f (fix f))`.
## Dokładamy `letrec` do naszego języka:
Wcześniej używaliśmy rzeczy z naszego metajęzyka do wykonywania rzeczy z języka, który interpretujemy.
```plait
env {letrec x e1 e2}
(letrec ([v (eval e1 (extend-env env x v))]) ;to nie zadziala, trzebaby to schowac pod lambde
(eval e2 (extend-env x v)))
```
Problem: mamy język gorliwy i liczymy wszystko, co się da (nawet gdy nie jest to nam potrzebne).
Działa to:
```plait
{letrec f {lambda {y} ... f ...}}
```
Ale nie działa to:
```plait
{letrec x {+ x 1} env}
```
Jak naprawić?
```plait
env {letrec x e1 e2}
(letrec ([v (eval e1 (extend-env env x (lambda () v)))]) ;bezargumentowa lamda zwracajaca wartosc, zeby ta wartosc nie probowala sie liczyc wczesniej
(eval e2 (extend-env x v)))
```
W ten sposób wyraziliśmy letrec'a z naszego języka letrec'iem z meta-języka.
## Można też zrobić letrec'a używając mutowalnego stanu