Semantyka i weryfikacja programów/Ćwiczenia 4

Z Studia Informatyczne
Przejdź do nawigacjiPrzejdź do wyszukiwania

Zawartość

Napiszemy semantykę naturalną języka wyrażeń (z 𝐥𝐞𝐭x=e1𝐢𝐧e2), rozważymy strategię gorliwą (jak na wcześniejszych zajęciach) i leniwą. Rozważymy i statyczne i dynamiczne wiązanie identyfikatorów. Następnie rozszerzymy ten język o lambda-abstrakcję i aplikację, otrzymując prosty język funkcyjny.


Różne semantyki wyrażeń

Zadanie 1 (semantyka gorliwa)

Napisz semantykę dużych kroków dla języka wyrażeń, którego semantykę mało-krokową napisaliśmy na jednych z poprzednich ćwiczeń:

n::=0|1|

x::=(identyfikatory)

e::=n|x|e1+e2|𝐢𝐟e1𝐭𝐡𝐞𝐧e2𝐞𝐥𝐬𝐞e3|𝐥𝐞𝐭x=e1𝐢𝐧e2

Rozwiązanie

Przypomnijmy, że zbiór stanów to 𝐒𝐭𝐚𝐭𝐞=𝐕𝐚𝐫fin𝐍𝐮𝐦

Nasze tranzycje będą postaci e,sn, gdzie e𝐄𝐱𝐩,s𝐒𝐭𝐚𝐭𝐞,n𝐍𝐮𝐦. Oto reguły semantyki naturalnej.

n,sn
x,sn o ile s(x)=n
e1,sn1e2,sn2e1+e2,sn o ile n=n1+n2
e1,sn1e2,s[xn]n2𝐥𝐞𝐭x=e1𝐢𝐧e2,sn2
e1,sn1n10e2,sn2𝐢𝐟e1𝐭𝐡𝐞𝐧e2𝐞𝐥𝐬𝐞e3,sn2
e1,sn1n1=0e3,sn3𝐢𝐟e1𝐭𝐡𝐞𝐧e2𝐞𝐥𝐬𝐞e3,sn3

Zwróćmy uwagę na fakt, że prawidłowe odwzorowanie zasięgu deklaracji x=e1 nie predstawia w semantyce naturalnej żadnych trudności, w przeciwieństwie do semantyki małych kroków.


Zadanie 2 (semantyka leniwa)

Zmodyfikuj semantykę z poprzedniego zadania, aby uzyskać leniwą ewaluację wyrażeń, zgodnie z dyrektywą: nie obliczaj wyrażenia o ile jego wynik nie jest potrzebny (albo: obliczaj wartość wyrażenia dopiero wtedy, gdy jego wynik jest naprawdę potrzebny). Spójrzmy na przykład:

𝐥𝐞𝐭x=7𝐢𝐧𝐥𝐞𝐭y=y+y𝐢𝐧x+x

Według semantyki z poprzedniego zadania wyrażnie to nie ma wartości, bo w deklaracji y=y+y jest odwołanie do niezainicjowanej zmiennej. Natomiast w semantyce leniwej wyrażenie to obliczy się do wartości 14, gdyż wyrażenie y+y nie będzie wogóle obliczane. Będzie tak dlatego, że w wyrażeniu x+x nie ma odwołań do zmiennej y.


Rozwiązanie

Semantyka leniwa będzie bardzo podobna do tej z poprzedniego zadania. Zasadnicza różnica dotyczy informacji przechowywanej w stanie. Dotychczas s(x) nalażał do zbioru 𝐍𝐮𝐦, gdyż podwyrażenie e w 𝐥𝐞𝐭x=e𝐢𝐧 obliczało sie natychmiast. Jeśli chcemy opóżnic obliczenie tego podwyrażenia, to w s(x) powinniśmy zapamiętać całe (nieobliczone) wyrażenie e wraz ze stanem bieżącym. Czyli

𝐒𝐭𝐚𝐭𝐞=𝐕𝐚𝐫fin𝐄𝐱𝐩×𝐒𝐭𝐚𝐭𝐞.

Np. odpowiednia reguła dla wyrażenia 𝐥𝐞𝐭 w semantyce małych kroków mogłaby wyglądać następująco:

𝐥𝐞𝐭x=e1𝐢𝐧e2,se2,s[x(e1,s)].

Czyli stan zawiera, dla każdej zmiennej, parę (wyrażenie definiujące, stan w momencie deklaracji).

Uważnego czytelnika zapewne zaniepokoił fakt, że 𝐒𝐭𝐚𝐭𝐞 stoi zarówno po lewej jak i po prawej stronie równania 𝐒𝐭𝐚𝐭𝐞=𝐕𝐚𝐫fin𝐄𝐱𝐩×𝐒𝐭𝐚𝐭𝐞. Również zapis s[x(e1,s)] może wzbudzić niepokój, gdyż sugeruje on, iż s(x) zawiera, jako jeden z elementów pary, obiekt tego samego typu co s. Formalnego rozwiązania tego typu dylematów dostarcza teoria dziedzin. Natomiast na użytek semantyki operacyjnej wystarczy, jeśli uznamy, iż równanie 𝐒𝐭𝐚𝐭𝐞=𝐕𝐚𝐫fin𝐄𝐱𝐩×𝐒𝐭𝐚𝐭𝐞 stanowi skrótowy zapis następującej definicji. Zdefiniujmy 𝐒𝐭𝐚𝐭𝐞0,𝐒𝐭𝐚𝐭𝐞1, następująco:

𝐒𝐭𝐚𝐭𝐞0={}

𝐒𝐭𝐚𝐭𝐞n+1=𝐕𝐚𝐫fin𝐄𝐱𝐩×𝐒𝐭𝐚𝐭𝐞n

i przyjmijmy, że

Parser nie mógł rozpoznać (nieznana funkcja „\nat”): {\displaystyle \mathbf{State} = \bigcup_{n \in \nat} \mathbf{State}_{n} }

Tranzycje będą znów postaci: e,sn. Podamy tylko reguły dla wystąpienia zmiennej i dla wyrażenia 𝐥𝐞𝐭. Pozostałe reguły pozostają praktyczanie bez zmian.

e,snx,sn o ile s(x)=(e,s)
e2,s[x(e1,s)]n𝐥𝐞𝐭x=e1𝐢𝐧e2,sn 


Zadanie 3 (semantyka dynamiczna)

Rozważmy teraz zupełnie inny mechanizm wiązania identyfikatorów, zwany wiązaniem dynamicznym. Dla odróżnienia, dotychczasowy sposób wiązania (widoczności) identyfikatorów będziemy nazywać wiązaniem statycznym. Oto przykładowe wyrażenie:

𝐥𝐞𝐭y=x+1𝐢𝐧𝐥𝐞𝐭x=10𝐢𝐧y

które nie ma wartości według semantyk z poprzednich zadań, ponieważ odwołanie do zmiennej x w deklaracji y=x+1 jest niepoprawne (w pustym stanie początkowym). Tak samo jest nawet w semantyce leniwej, gdyż wartość zmiennej y będzie w końcu policzona, i będzie wymagała odwołania do x w stanie pustym.

Natomiast wyobrażmy sobie, że zmieniamy semantykę leniwą następująco: odwołanie do zmiennej x podczas obliczania wartości y będzie odnosiło się nie do stanu w momencie deklaracji y, ale do stanu w momencie odwołania do y. Jest to dość rewolucyjna zmiana, zapewne sprzeczna z intuicjami programisty (statyczne reguły widoczności zamieniamy na dynamiczne). W szczególności powyższe wyrażenie policzy się w semantyce dynamicznej do wartości 11, ponieważ stan w momencie odwołania do zmiennej y przypisuje zmiennej x wartość 10 !

Napisz semantykę naturalną dla wiązania dynamicznego.


Rozwiązanie

Teraz w stanie wystarczy przechowywać wyrażenie definiujące wartość danej zmiennej:

𝐒𝐭𝐚𝐭𝐞=𝐕𝐚𝐫fin𝐄𝐱𝐩.

Nie potrzebujemy zapamiętywać stanu, w którym byliśmy w momencie deklaracji. Do obliczenia zapamiętanego wyrażenia użyjemy stanu, w którym będziemy w momencie odwołania do danej zmiennej. Znów podajemy tylko reguły dla wystąpienia zmiennej i dla wyrażenia 𝐥𝐞𝐭, gdyż pozostałe reguły pozostają bez zmian

e,snx,sn o ile s(x)=e 
e2,s[xe1]n𝐥𝐞𝐭x=e1𝐢𝐧e2,sn

Pytanie: czy 𝐥𝐞𝐭x=x+1𝐢𝐧x oblicza się do jakiejś wartości w stanie ?


Prosty język funkcyjny

Zadanie 1

Rozszerzmy język wyrażeń następująco:

e::=|λx.e|e1(e2)

Lambda-abstrakcja λx.e reprezentuje anonimową (nienazwaną) funkcję jednoargumentową, natomiast wyrażenie e1(e2) to aplikacja e1 do e2 (wyrażenie e1 powinno zatem obliczać się do funkcji). Np. (lambdax.x+3)(2)5.

Przyjmijmy statyczną widoczność identyfikatorów. Możliwe są różne mechanizmy przekazywania parametrów. Rozważmy dwa:

  • przez wartość
  • przez nazwę

Pierwszy z nich jest zapewne doskonale znany Czytelnikowi: wyrażenie będące parametrem aktualnym jest obliczane przed wywołaniem funkcji, czyli w stanie, w którym jesteśmy z momencie wywołania funkcji. Drugi stanowi jakby leniwy odpowiednik przekazywania przez wartość: nie obliczamy wyrażenia będącego parametrem aktualnym, a zamiast jego wartości przekazujemy do funkcji to wyrażenie wraz ze stanem z miejsca wywołania funkcji. To ten stan bedzie brany pod uwagę, gdy obliczana będzie wartość parametru, tzn. przy odwołaniu w ciele funkcji do parametru formalnego.

Zaproponuj semantykę naturalną dla tego języka dla obydwu mechanizmów przekazywania parametrów (w dwóch wariantach).


Rozwiązanie

....


Zadanie 2

Zaproponuj dynamiczne odpowiedniki obydwu semantyk z poprzedniego zadania.


Rozwiązanie

....


Zadania domowe

Zadanie 1

Podaj przykład wyrażenia takiego, które:

  • ma wartość w semantyce statycznej i dynamicznej, ale w każdej inną
  • ma wartość w semantyce leniwej a nie ma w dynamicznej
  • ma wartość w semantyce dynamicznej a nie ma w leniwej


Zadanie 2

W semantyce leniwej wyrażeń, jeśli jest wiele odwołań do jakiejś zmiennej, to obliczenie wartości tej zmiennej nastąpi za każdym razem od nowa. Zmoddyfikuj tę semantykę tak, aby po pierwszym odwołaniu do zmiennej, obliczona wartość tej zmiennej była umieszczana w stanie, zastępując parę (wyrażenie, stan).