24.01.2014 Views

Programowanie funkcyjne - Wykład 13. Siła wyrazu rachunku lambda

Programowanie funkcyjne - Wykład 13. Siła wyrazu rachunku lambda

Programowanie funkcyjne - Wykład 13. Siła wyrazu rachunku lambda

SHOW MORE
SHOW LESS

Create successful ePaper yourself

Turn your PDF publications into a flip-book with our unique Google optimized e-Paper software.

<strong>Programowanie</strong> <strong>funkcyjne</strong><br />

<strong>Wykład</strong> <strong>13.</strong> <strong>Siła</strong> <strong>wyrazu</strong> <strong>rachunku</strong> <strong>lambda</strong><br />

Zdzisław Spławski<br />

Zdzisław Spławski: <strong>Programowanie</strong> <strong>funkcyjne</strong>, <strong>Wykład</strong> <strong>13.</strong> <strong>Siła</strong> <strong>wyrazu</strong> <strong>rachunku</strong> <strong>lambda</strong> 1


Wstęp<br />

Wartości logiczne<br />

Liczby naturalne jako liczebniki Churcha<br />

Kombinatory punktu stałego<br />

Reguły delta<br />

Reprezentowalność funkcji rekurencyjnych w λ-<strong>rachunku</strong><br />

Kombinator punktu stałego w OCamlu<br />

Semantyka prostego języka imperatywnego<br />

Zadania kontrolne<br />

Zdzisław Spławski: <strong>Programowanie</strong> <strong>funkcyjne</strong>, <strong>Wykład</strong> <strong>13.</strong> <strong>Siła</strong> <strong>wyrazu</strong> <strong>rachunku</strong> <strong>lambda</strong> 2


Wstęp<br />

Język funkcyjny można potraktować jak rachunek <strong>lambda</strong> (beztypowy<br />

lub z typami) z wybraną semantyką redukcyjną, dodanymi stałymi (z<br />

odpowiednimi regułami redukcji) i dużą ilością „lukru syntaktyczego”.<br />

Te rozszerzenia <strong>rachunku</strong> <strong>lambda</strong> stosuje się w celu ułatwienia pisania<br />

programów, polepszenia ich czytelności i zwiększenia efektywności.<br />

Logicznie nie są one koniecznie.<br />

Jako przykłady zostaną zdefiniowane wartości logiczne i liczby<br />

naturalne z odpowiednimi funkcjami jako termy <strong>rachunku</strong> <strong>lambda</strong>.<br />

Zostaną też podane najważniejsze twierdzenia świadczące o sile<br />

<strong>wyrazu</strong> <strong>rachunku</strong> <strong>lambda</strong>.<br />

Zdzisław Spławski: <strong>Programowanie</strong> <strong>funkcyjne</strong>, <strong>Wykład</strong> <strong>13.</strong> <strong>Siła</strong> <strong>wyrazu</strong> <strong>rachunku</strong> <strong>lambda</strong> 3


Wartości logiczne<br />

Specyfikacja algebraiczna:<br />

if true M N = M<br />

if false M N = N<br />

Odpowiednie termy można zdefiniować na przykład tak<br />

(Church):<br />

true ≡ λxy.x false ≡ λxy.y if ≡ λbuv.buv (↠ η λb.b)<br />

Udowodnimy, że spełnione jest pierwsze równanie specyfikacji.<br />

if true M N ≡ (λbuv.b u v) true M N → β (λuv.true u v)M N<br />

→ β (λv.true M v) N → β true M N<br />

≡ (λxy.x) M N → β (λy.M)N<br />

→ β M<br />

Analogicznie wygląda dowód drugiego równania.<br />

W celu zwiększenia czytelności czasem zamiast if B M N<br />

będziemy pisali if BthenMelseN.<br />

Zdzisław Spławski: <strong>Programowanie</strong> <strong>funkcyjne</strong>, <strong>Wykład</strong> <strong>13.</strong> <strong>Siła</strong> <strong>wyrazu</strong> <strong>rachunku</strong> <strong>lambda</strong> 4


Liczby naturalne jako liczebniki Churcha<br />

Specyfikacja algebraiczna:<br />

{<br />

Iter 0 M N = N<br />

Iter (suc n) M N = M(Iter n M N)<br />

Odpowiednie termy można zdefiniować na różne sposoby, np.<br />

liczebniki Churcha są zdefiniowane następująco:<br />

0 ≡ λfx.x 1 ≡ λfx.fx 2 ≡ λfx.f(fx) itd.<br />

Możemy to uogólnić i zauważyć, że liczebnik reprezentujący<br />

liczbę n będzie miał postać λfx.f n x, czyli jest iteratorem.<br />

Wobec tego definiujemy:<br />

suc ≡ λnfx.f(nfx) Iter ≡ λnfa.nfa (↠ η λn.n)<br />

lub suc ≡ λnfx.nf(fx)<br />

Zdzisław Spławski: <strong>Programowanie</strong> <strong>funkcyjne</strong>, <strong>Wykład</strong> <strong>13.</strong> <strong>Siła</strong> <strong>wyrazu</strong> <strong>rachunku</strong> <strong>lambda</strong> 5


Kombinatory punktu stałego<br />

Równania stałopunktowe w matematyce.<br />

Rozważmy równania algebraiczne, np.<br />

x = 5/x czy x = 6 − x<br />

Problem rozwiązania tych równań można też sformułować jako<br />

problem znalezienia punktów stałych funkcji:<br />

f 1 ≡ λx.5/x i f 2 ≡ λx.6 − x<br />

Punktem stałym funkcji jest wartość należąca do dziedziny<br />

funkcji , odwzorowywana przez funkcję na siebie. Poszukujemy<br />

więc takich wartości w 1 i w 2 , że<br />

f 1 w 1 = w 1 i f 2 w 2 = w 2<br />

Oczywiście w 1 = √ 5 i w 2 = 3.<br />

Punkt stały może być jeden, może ich być wiele (nawet<br />

nieskończenie wiele), może też nie być żadnego. Istnienie i liczba<br />

punktów stałych funkcji istotnie zależy od jej dziedziny.<br />

Zdzisław Spławski: <strong>Programowanie</strong> <strong>funkcyjne</strong>, <strong>Wykład</strong> <strong>13.</strong> <strong>Siła</strong> <strong>wyrazu</strong> <strong>rachunku</strong> <strong>lambda</strong> 6


Kombinatory punktu stałego<br />

Równania stałopunktowe w programowaniu.<br />

Podobny problem pojawia się przy definicjach funkcji<br />

rekurencyjnych, np.<br />

lub inaczej:<br />

s(n) = if n = 0 then 1 else n ∗ s(n − 1)<br />

s = λn.if n = 0 then 1 else n ∗ s(n − 1)<br />

Z matematycznego punktu widzenia jest to równanie (wyższego<br />

rzędu) z jedną niewiadomą s. Symbol = oznacza tu β (lub βη)<br />

konwersję. Problem rozwiązania tego równania, tj. znalezienia<br />

<strong>lambda</strong> termu, spełniającego równanie, sprowadza się do<br />

znalezienia punktu stałego funkcjonału:<br />

F ≡ λfn.if n = 0 then 1 else n ∗ f(n − 1)<br />

Zdzisław Spławski: <strong>Programowanie</strong> <strong>funkcyjne</strong>, <strong>Wykład</strong> <strong>13.</strong> <strong>Siła</strong> <strong>wyrazu</strong> <strong>rachunku</strong> <strong>lambda</strong> 7


Kombinatory punktu stałego<br />

Kombinator punktu stałego<br />

Definicja. Kombinatorem punktu stałego nazywamy każdy term M<br />

taki, że ∀F.MF = F (MF ).<br />

Twierdzenie o punkcie stałym.<br />

Dowód.<br />

(i) ∀F.∃X.X = F X<br />

(ii) Istnieje kombinator punktu stałego<br />

Y ≡ λf.(λx.f(xx))(λx.f(xx)) taki, że YF = F (YF ).<br />

(i) Niech W ≡ λx.F (xx) i X ≡ W W . Wówczas<br />

X ≡ W W ≡ (λx.F (xx))W → F (W W ) ≡ F X<br />

(ii) YF ≡ (λf.(λx.f(xx))(λx.f(xx)))F<br />

→ β (λx.F (xx))(λx.F (xx))<br />

→ β F ((λx.F (xx))(λx.F (xx)))<br />

= β F ((λf.(λx.f(xx))(λx.f(xx)))F ) ≡ F (YF )<br />

Zdzisław Spławski: <strong>Programowanie</strong> <strong>funkcyjne</strong>, <strong>Wykład</strong> <strong>13.</strong> <strong>Siła</strong> <strong>wyrazu</strong> <strong>rachunku</strong> <strong>lambda</strong> 8


Kombinatory punktu stałego<br />

Kombinator Turinga<br />

Czasem potrzebujemy kombinatora punktu stałego M z nieco<br />

mocniejszą własnością:<br />

∀F.MF ↠ β F (MF ).<br />

Turing zaproponował następujący kombinator:<br />

Θ ≡ AA<br />

gdzie A ≡ λxy.y(xxy).<br />

ΘF ≡ (λxy.y(xxy))AF<br />

→ β (λy.y(AAy))F<br />

→ β F (AAF )<br />

≡ F (ΘF )<br />

Zauważ, że dla kombinatora Y można udowodnić tylko<br />

YF = β F (YF ).<br />

Istnieje nieskończenie wiele kombinatorów punktu stałego.<br />

Zdzisław Spławski: <strong>Programowanie</strong> <strong>funkcyjne</strong>, <strong>Wykład</strong> <strong>13.</strong> <strong>Siła</strong> <strong>wyrazu</strong> <strong>rachunku</strong> <strong>lambda</strong> 9


Kombinatory punktu stałego<br />

Przykład użycia kombinatora punktu stałego: silnia.<br />

Teraz możemy zdefiniować <strong>lambda</strong> term dla silni jako:<br />

s ≡ YF (lub ΘF ) gdzie F ≡ λfn.if n = 0 then 1 else n ∗ f(n − 1)<br />

Uwaga. Przy ewaluacji tego termu należy stosować redukcję<br />

normalną.<br />

s n ≡ (Y F ) n<br />

= β F (Y F ) n<br />

≡<br />

(λfn.if n = 0 then 1 else n ∗ f(n − 1))(Y F ) n<br />

↠ β if n = 0 then 1 else n ∗ (Y F )(n − 1)<br />

≡ if n = 0 then 1 else n ∗ s(n − 1)<br />

Oczywiście, możliwa jest inna definicja silni za pomocą<br />

iteratora, co odpowiadałoby rekursji ogonowej.<br />

Zdzisław Spławski: <strong>Programowanie</strong> <strong>funkcyjne</strong>, <strong>Wykład</strong> <strong>13.</strong> <strong>Siła</strong> <strong>wyrazu</strong> <strong>rachunku</strong> <strong>lambda</strong> 10


Kombinatory punktu stałego<br />

Powyższy przykład możemy uogólnić.<br />

Twierdzenie. Niech C ≡ C[f, ⃗x] będzie termem ze zmiennymi<br />

wolnymi f i ⃗x. Wówczas:<br />

(i) ∃F.∀ ⃗ N.F ⃗ N = C[F, ⃗ N]<br />

(ii) ∃F.∀ ⃗ N.F ⃗ N ↠ β C[F, ⃗ N]<br />

Dowód. W obu przypadkach możemy wziąć<br />

F ≡ Θ(λf⃗x.C[f, ⃗x]). Zauważ, że dla przypadku (i) wystarczy<br />

wziąć Y.<br />

Zdzisław Spławski: <strong>Programowanie</strong> <strong>funkcyjne</strong>, <strong>Wykład</strong> <strong>13.</strong> <strong>Siła</strong> <strong>wyrazu</strong> <strong>rachunku</strong> <strong>lambda</strong> 11


Reguły delta<br />

Reguły delta<br />

Definicja.<br />

(i) Niech δ będzie pewną stałą. Wówczas Λδ jest zbiorem λ-termów<br />

zbudowanych ze zmiennych i stałej δ za pomocą aplikacji i<br />

abstrakcji w zwykły sposób.<br />

(ii) Analogicznie definiuje się Λ ⃗ δ, gdzie ⃗ δ oznacza ciąg stałych.<br />

(iii) Niech ⃗ M oznacza ciąg zamkniętych λ-termów w postaci<br />

normalnej. δ-redukcja ma postać δ ⃗ M → δ f( ⃗ M).<br />

Dla zadanej funkcji f δ-redukcja nie jest pojedynczą regułą, lecz<br />

schematem reguł. Tak wzbogacony system nazywamy rachunkiem λδ.<br />

Relacje kontrakcji i redukcji są oznaczane odpowiednio przez → βδ<br />

i ↠ βδ .<br />

Zdzisław Spławski: <strong>Programowanie</strong> <strong>funkcyjne</strong>, <strong>Wykład</strong> <strong>13.</strong> <strong>Siła</strong> <strong>wyrazu</strong> <strong>rachunku</strong> <strong>lambda</strong> 12


Reguły delta<br />

Reguły delta<br />

Twierdzenie. Niech f będzie funkcją na zamkniętych λ-termach w<br />

postaci normalnej. Wówczas relacja redukcji ↠ βδ spełnia twierdzenie<br />

Churcha-Rossera.<br />

Pojęcie redeksu, postaci normalnej i strategii redukcji w sposób<br />

naturalny uogólnia się na rachunek λδ. Prawdziwe jest też twierdzenie<br />

o standardyzacji.<br />

Zdzisław Spławski: <strong>Programowanie</strong> <strong>funkcyjne</strong>, <strong>Wykład</strong> <strong>13.</strong> <strong>Siła</strong> <strong>wyrazu</strong> <strong>rachunku</strong> <strong>lambda</strong> 13


Reguły delta<br />

Przykład: test na zero<br />

W wielu funkcjach konieczne jest sprawdzenie, czy liczba jest<br />

równa zeru. Specyfikacja takiego predykatu wygląda<br />

następujaco: {<br />

isZero 0 = true<br />

isZero (suc n) = false<br />

Spełnia ona wymagania twierdzenia z poprzedniej strony ( przy<br />

założeniu, że n oznacza term zamknięty), więc moglibyśmy<br />

dodać do λ-termów stałą isZero oraz dwie reguły redukcji, nie<br />

troszcząc się o znalezienie termu, spełniającego powyższą<br />

specyfikację.<br />

My jednak podamy ten term.<br />

isZero ≡ λn.Iter n (λb.false) true<br />

Łatwo pokazać, że spełnia on powyższą specyfikację.<br />

Analogicznie należy rozumieć następny przykład.<br />

Zdzisław Spławski: <strong>Programowanie</strong> <strong>funkcyjne</strong>, <strong>Wykład</strong> <strong>13.</strong> <strong>Siła</strong> <strong>wyrazu</strong> <strong>rachunku</strong> <strong>lambda</strong> 14


Reguły delta<br />

Przykład: poprzednik<br />

{<br />

pred 0 = 0<br />

pred (suc n) = n<br />

Ideę obliczania poprzednika wyjaśnia poniższy program.<br />

}<br />

y := 0;<br />

〈0, 0〉<br />

z := 0;<br />

⎫<br />

while y ≠ n do (∗ z = pred y ∗)<br />

begin<br />

}<br />

⎪⎬<br />

z := y;<br />

n-krotna iteracja operacji q<br />

q〈y, z〉 → 〈suc y, y〉<br />

y := suc y;<br />

⎪⎭<br />

end<br />

(∗ z = pred n ∗)<br />

Teraz ten algorytm możemy zapisać w postaci <strong>lambda</strong>-termu.<br />

pred ≡ λn.snd (Iter n (λp.pair(suc(fst p))(fst p)) (pair 0 0))<br />

Zdzisław Spławski: <strong>Programowanie</strong> <strong>funkcyjne</strong>, <strong>Wykład</strong> <strong>13.</strong> <strong>Siła</strong> <strong>wyrazu</strong> <strong>rachunku</strong> <strong>lambda</strong> 15


Reprezentowalność funkcji rekurencyjnych w λ-<strong>rachunku</strong><br />

Definicja. Funkcja częściowo rekurencyjna f : N k → N jest<br />

definiowalna w beztypowym <strong>rachunku</strong> <strong>lambda</strong>, jeśli istnieje<br />

zamknięty term F , spełniający dla dowolnych n 1 . . . n k ∈ N<br />

następujące warunki:<br />

(i) Jeśli f(n 1 . . . n k ) = m, to F n 1 . . . n k = β m;<br />

(ii) Jeśli wartość f(n 1 . . . n k ) jest nieokreślona, to F n 1 . . . n k<br />

nie ma postaci normalnej.<br />

Zdzisław Spławski: <strong>Programowanie</strong> <strong>funkcyjne</strong>, <strong>Wykład</strong> <strong>13.</strong> <strong>Siła</strong> <strong>wyrazu</strong> <strong>rachunku</strong> <strong>lambda</strong> 16


Reprezentowalność funkcji rekurencyjnych w λ-<strong>rachunku</strong><br />

Lemat. Funkcje bazowe (początkowe) Z, S, U i n są<br />

λ-definiowalne.<br />

Dowód. Weźmy następujące kombinatory jako termy<br />

definiujące.<br />

Z ≡ λn.0<br />

suc ≡ λnfx.f(nfx)<br />

U i n ≡ λx 1 . . . x n .x i<br />

Lemat. Funkcje λ-definiowalne są zamknięte ze względu na<br />

operację składania funkcji.<br />

Dowód. Niech funkcje g, h 1 , . . . , h r będą λ-definiowalne<br />

odpowiednio za pomocą termów G, H 1 , . . . , H r . Wówczas<br />

funkcja<br />

f(⃗x) = g(h 1 (⃗x), . . . , h r (⃗x))<br />

jest λ-definiowalna za pomocą termu<br />

F ≡ λ⃗x.G(H 1 ⃗x) . . . (H r ⃗x)<br />

Zdzisław Spławski: <strong>Programowanie</strong> <strong>funkcyjne</strong>, <strong>Wykład</strong> <strong>13.</strong> <strong>Siła</strong> <strong>wyrazu</strong> <strong>rachunku</strong> <strong>lambda</strong> 17


Reprezentowalność funkcji rekurencyjnych w λ-<strong>rachunku</strong><br />

Lemat. Funkcje λ-definiowalne są zamknięte ze względu na<br />

rekursję { prostą.<br />

{<br />

Rec g h 0 ⃗x = g ⃗x<br />

f(0, ⃗x) = g(⃗x),<br />

Rec g h (suc n) ⃗x = h n (Rec g h n ⃗x) ⃗x<br />

f(S(n), ⃗x) = h(n, f(n, ⃗x), ⃗x),<br />

Ideę obliczania rekursora wyjaśnia poniższy program (porównaj<br />

z programem dla poprzednika).<br />

}<br />

y := 0;<br />

〈0, g(⃗x)〉<br />

z := g(⃗x);<br />

⎫<br />

while y ≠ n do (∗ z = f(y, ⃗x) ∗)<br />

begin }<br />

⎪⎬<br />

n-krotna iteracja<br />

z := h(y, z, ⃗x);<br />

q〈y, z〉 → 〈suc y, h(y, z, ⃗x)〉 operacji q<br />

y := suc y;<br />

⎪⎭<br />

end<br />

(∗ z = f(n, ⃗x) ∗)<br />

Teraz ten algorytm możemy zapisać w postaci λ-termu.<br />

Rec ≡<br />

λghn⃗x.snd (Iter n (λp.pair (suc (fst p)) (h (fst p) (snd p) ⃗x)) (pair 0 (g⃗x))<br />

Zdzisław Spławski: <strong>Programowanie</strong> <strong>funkcyjne</strong>, <strong>Wykład</strong> <strong>13.</strong> <strong>Siła</strong> <strong>wyrazu</strong> <strong>rachunku</strong> <strong>lambda</strong> 18


Reprezentowalność funkcji rekurencyjnych w λ-<strong>rachunku</strong><br />

Lemat. Funkcje λ-definiowalne są zamknięte ze względu na<br />

operację minimum.<br />

Dowód. Niech funkcja g będzie λ-definiowalna za pomocą<br />

termu G. Wówczas funkcja f(⃗x) = (µm.g(⃗x, m) = 0) jest<br />

λ-definiowalna za pomocą termu<br />

mi ≡ λ⃗x.szukaj 0 ⃗x (↠ η szukaj 0)<br />

gdzie<br />

szukaj ≡ Θ λfm⃗x.if isZero (G ⃗x m) then m else f (suc m) ⃗x.<br />

Ponieważ Θ F ↠ F (Θ F ), to<br />

szukaj m ⃗x ↠ if isZero (G ⃗x m) then m else szukaj (suc m) ⃗x<br />

Wobec tego szukaj 0 ⃗x zaczynając od zera poszukuje<br />

najmniejszej liczby m takiej, że (G ⃗x m) = 0, co jest zgodne z<br />

definicją operacji minimum.<br />

Zdzisław Spławski: <strong>Programowanie</strong> <strong>funkcyjne</strong>, <strong>Wykład</strong> <strong>13.</strong> <strong>Siła</strong> <strong>wyrazu</strong> <strong>rachunku</strong> <strong>lambda</strong> 19


Reprezentowalność funkcji rekurencyjnych w λ-<strong>rachunku</strong><br />

Twierdzenie. Wszystkie funkcje częściowo rekurencyjne są<br />

λ-definiowalne.<br />

Teza Churcha [Churcha-Turinga]. Każda funkcja obliczalna<br />

w nieformalnym sensie jest λ-definiowalna (rekurencyjna).<br />

Zdzisław Spławski: <strong>Programowanie</strong> <strong>funkcyjne</strong>, <strong>Wykład</strong> <strong>13.</strong> <strong>Siła</strong> <strong>wyrazu</strong> <strong>rachunku</strong> <strong>lambda</strong> 20


Kombinator punktu stałego w OCamlu<br />

Kombinator punktu stałego w OCamlu. I<br />

Bezpośrednia definicja kombinatora Y ≡ λf.(λx.f(xx))(λx.f(xx))<br />

w języku OCaml spowoduje błąd typu. Możemy jednak zdefiniować<br />

typ danych:<br />

type ’a self = Fold of (’a self -> ’a);;<br />

let unfold (Fold t) = t;;<br />

a następnie funkcjonał fixl : (’a -> ’a) -> ’a<br />

let fixl f =<br />

let w = fun x -> f ( unfold x x) in w (Fold w);;<br />

który działa poprawnie dla dla języków z wartościowaniem leniwym.<br />

W OCamlu, który stosuje wartościowanie gorliwie, wartościowanie<br />

fixl nie kończy się i nie uda się nam zdefiniować np. nieskończonej<br />

listy jedynek (sprawdź to!):<br />

let ones = fixl (function x -> 1::x);;<br />

Zdzisław Spławski: <strong>Programowanie</strong> <strong>funkcyjne</strong>, <strong>Wykład</strong> <strong>13.</strong> <strong>Siła</strong> <strong>wyrazu</strong> <strong>rachunku</strong> <strong>lambda</strong> 21


Kombinator punktu stałego w OCamlu<br />

Kombinator punktu stałego w OCamlu. II<br />

Można jednak nieco zmodyfikować powyższy funkcjonał i otrzymać<br />

funkcjonał:<br />

let fix f = let w = fun x y-> f (unfold x x) y<br />

in w (Fold w);;<br />

val fix : ((’a -> ’b) -> ’a -> ’b) -> ’a -> ’b = <br />

który znajduje punkty stałe funkcji (ale już nie list!). Przekonaj się o<br />

tym, definiując funkcję obliczającą silnię zadanej liczby bez jawnego<br />

użycia rekursji.<br />

Funkcjonał fix : ((’a -> ’b) -> ’a -> ’b) -> ’a -> ’b<br />

można też zdefiniować bez użycia typu ’a self, np.<br />

let fix f = let rec fixf x = f fixf x in fixf;;<br />

Można go teraz użyć do zdefiniowania silni bez użycia rekursji:<br />

let fact = fix (fun f n -> if n=0 then 1 else n*f(n-1));;<br />

Przekonaj się, że jest to rzeczywiście funkcja silni.<br />

Zdzisław Spławski: <strong>Programowanie</strong> <strong>funkcyjne</strong>, <strong>Wykład</strong> <strong>13.</strong> <strong>Siła</strong> <strong>wyrazu</strong> <strong>rachunku</strong> <strong>lambda</strong> 22


Semantyka prostego języka imperatywnego<br />

Składnia i semantyka prostego języka imperatywnego. I<br />

Składnia abstrakcyjna<br />

V ∈ Zmienna<br />

N ∈ Liczba<br />

B ::= true | false | B&&B | B||B | not B | E < E | E = E<br />

E ::= N | V | E + E | E ∗ E | E − E | −E<br />

C ::= skip | C; C | V := E | if B then C else C fi | while B do C od<br />

Semantykę denotacyjną języka zadaje się definiując funkcje<br />

semantyczne, które opisują, jak semantyka wyrażenia może być<br />

otrzymana z semantyki składowych tego wyrażenia (semantyka<br />

kompozycyjna).<br />

Zdzisław Spławski: <strong>Programowanie</strong> <strong>funkcyjne</strong>, <strong>Wykład</strong> <strong>13.</strong> <strong>Siła</strong> <strong>wyrazu</strong> <strong>rachunku</strong> <strong>lambda</strong> 23


Semantyka prostego języka imperatywnego<br />

Składnia i semantyka prostego języka imperatywnego. II<br />

Funkcja semantyczna dla instrukcji C jest funkcją częściową S C [C ] ,<br />

zmieniającą wektor stanu programu S (pamięć operacyjną). Dziedzinę<br />

S reprezentujemy za pomocą zbioru funkcji σ : Zmienna → Z.<br />

Załóżmy dla uproszczenia, że funkcje semantyczne dla wyrażeń<br />

logicznych B i arytmetycznych E są znane. Tutaj zdefiniujemy w<br />

<strong>rachunku</strong> <strong>lambda</strong> funkcję semantyczną S C [C ] : S S dla instrukcji.<br />

Na wykładzie 3 zaprogramowaliśmy ją w OCamlu.<br />

Semantyka denotacyjna<br />

S B [B ] : S → {true, false}<br />

S E [E ] : S → Z<br />

S C [skip]σ = σ<br />

S C [C 1 ; C 2 ]σ ≃ S C [C 2 ](S C [C 1 ]σ)<br />

S C [V := E ]σ ≃ σ[V ↦→ S E [E ]σ]<br />

{<br />

SC [C<br />

S C [if B then C 1 else C 2 fi]σ ≃<br />

1 ]σ gdy S E [B ]σ = true<br />

S C [C 2 ]σ gdy S E [B ]σ = false<br />

Zdzisław Spławski: <strong>Programowanie</strong> <strong>funkcyjne</strong>, <strong>Wykład</strong> <strong>13.</strong> <strong>Siła</strong> <strong>wyrazu</strong> <strong>rachunku</strong> <strong>lambda</strong> 24


Semantyka prostego języka imperatywnego<br />

Składnia i semantyka prostego języka imperatywnego. III<br />

Wykonując jednokrotnie pętlę while otrzymujemy poniższe równanie<br />

dla funkcji semantycznej S C [while B do C od]:<br />

{ SC[[while B do C od]](S C[[C]]σ) gdy S B[[B]]σ = true<br />

S C[[while B do C od]]σ ≃<br />

σ<br />

gdy S B[[B]]σ = false<br />

Z analogicznym problemem mieliśmy do czynienia w przypadku<br />

funkcji silnia. Należy znaleźć najmniejszy punkt stały funkcjonału:<br />

{<br />

f(SC [C ]σ) gdy S<br />

F ≡ λf.λσ.<br />

B [B ]σ = true<br />

σ<br />

gdy S B [B ]σ = false<br />

czyli, używając kombinatora punktu stałego Θ (lub Y):<br />

S C [while B do C od] ≃ ΘF<br />

Istnienie najmniejszego punktu stałego gwarantuje teoria dziedzin.<br />

Zdzisław Spławski: <strong>Programowanie</strong> <strong>funkcyjne</strong>, <strong>Wykład</strong> <strong>13.</strong> <strong>Siła</strong> <strong>wyrazu</strong> <strong>rachunku</strong> <strong>lambda</strong> 25


Zadania kontrolne<br />

1. Wykorzystując term if zdefiniuj pozostałe spójniki logiczne.<br />

2. Udowodnij, że termy 0, suc, Iter spełniają specyfikację<br />

algebraiczną ze strony 5.<br />

3. Zdefiniuj <strong>lambda</strong> wyrażenia pair, fst i snd z następującymi<br />

regułami redukcji:<br />

fst (pair M N) ↠ M<br />

snd (pair M N) ↠ N<br />

4. Niech Y ≡ λf.(λx.f(xx))(λx.f(xx)), S ≡ λxyz.xz(yz),<br />

I ≡ λx.x. Udowodnij, że wszystkie kombinatory<br />

zdefiniowane następująco:<br />

{<br />

Y 0 ≡ Y<br />

Y n+1 ≡ Y n (SI)<br />

są kombinatorami punktu stałego.<br />

5. Pokaż, że Y 1 ↠ β Θ.<br />

6. Zdefiniuj kombinator Θ w OCamlu.<br />

Zdzisław Spławski: <strong>Programowanie</strong> <strong>funkcyjne</strong>, <strong>Wykład</strong> <strong>13.</strong> <strong>Siła</strong> <strong>wyrazu</strong> <strong>rachunku</strong> <strong>lambda</strong> 26

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!