Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revision Previous revision
Next revision
Previous revision
pp:2024:tema3 [2024/05/01 12:49]
tpruteanu
pp:2024:tema3 [2024/05/03 09:49] (current)
tpruteanu
Line 2: Line 2:
  
 <​note>​ <​note>​
-Schelet: ​TODO+Schelet: ​{{:​pp:​2024:​lambda-interpreter.zip|}}
 </​note>​ </​note>​
  
 <note warning> <note warning>
-**Deadline:​** ​TODO+**Deadline:​** ​miercuri 29 mai, ora 23:59
   * Temele trebuie submise pe [[curs.upb.ro]],​ în assignment-ul ''​Tema 3''​.   * Temele trebuie submise pe [[curs.upb.ro]],​ în assignment-ul ''​Tema 3''​.
   * Pentru întrebări folosiți forum-ul dedicat de pe [[curs.upb.ro]].   * Pentru întrebări folosiți forum-ul dedicat de pe [[curs.upb.ro]].
Line 17: Line 17:
 </​note>​ </​note>​
  
-sa definim o expresie lambda cu ajutorul ​urmatorului ​**TDA**:+să definim o expresie lambda cu ajutorul ​următorului ​**TDA**:
 <code haskell> <code haskell>
 data Lambda = Var String data Lambda = Var String
Line 25: Line 25:
  
 <note important>​ <note important>​
-In schelet, ​definitia ​**TDA**-ului ​contine si un constructor pentru macro-uri, pentru ​cerintele ​**1** si **2** il puteti ​ignora, o sa puteti ​lua punctaj maxim fara sa faceti ​pattern matching pe el, o sa fie introdus ​in cadrul ​cerintei ​**3**.+În schelet, ​definiția ​**TDA**-ului ​conține și un constructor pentru macro-uri, pentru ​cerințele ​**1** și **2** îl puteți ​ignora, o să puteți ​lua punctaj maxim fără să faceți ​pattern matching pe el, o să fie introdus ​în cadrul ​cerinței ​**3**.
 </​note>​ </​note>​
  
-Variabilele sunt declarate de tipul ''​String'',​ pentru simplitate o sa considerăm ​variabila ​orice șir de caractere format numai din litere mici ale alfabetului englez.+Variabilele sunt declarate de tipul ''​String'',​ pentru simplitate o să considerăm ​variabilă ​orice șir de caractere format numai din litere mici ale alfabetului englez.
  
 ===== 1. Evaluation ===== ===== 1. Evaluation =====
Line 38: Line 38:
 </​note>​ </​note>​
  
-Evaluarea unei //expresii lambda// ​consta in realizarea de $\beta$-reducerii ​pana ajungem la o expresie ​echivalenta in forma normala.+Evaluarea unei //expresii lambda// ​constă în realizarea de $\beta$-reducerii ​până ​ajungem la o expresie ​echivalentă în formă normală.
  
-Un detaliu de implementare este ca inainte ​de a realiza $\beta$-reducerea,​ va trebui să rezolvăm posibilele //​**coliziuni de nume**//. \\+Un detaliu de implementare este că înainte ​de a realiza $\beta$-reducerea,​ va trebui să rezolvăm posibilele //​**coliziuni de nume**//. \\
 Dacă am încerca să reducem un **redex** fără a face substituții textuale există riscul de a pierde întelesul original al expresiei. \\ Dacă am încerca să reducem un **redex** fără a face substituții textuale există riscul de a pierde întelesul original al expresiei. \\
-Spre exemplu **redex**-ul:​ $(\lambda x.\lambda y.(x \ y) \ \lambda x.y)$, ar fi redus la: $\lambda y.(\lambda x.y \ y)$. Acest efect nedorit are denumirea intuitivă de //​variable-capture//:​ Variabila inițial liberă $math[y] a devenit legată ​dupa reducere. \\+Spre exemplu **redex**-ul:​ $(\lambda x.\lambda y.(x \ y) \ \lambda x.y)$, ar fi redus la: $\lambda y.(\lambda x.y \ y)$. Acest efect nedorit are denumirea intuitivă de //​variable-capture//:​ Variabila inițial liberă $math[y] a devenit legată ​după reducere. \\
 Puteți observa că expresia și-a pierdut sensul original, pentru că **y**-ul liber din $\lambda x.y$ e acum //bound// de $\lambda y.$ din expresia în care a fost înlocuit. \\ Puteți observa că expresia și-a pierdut sensul original, pentru că **y**-ul liber din $\lambda x.y$ e acum //bound// de $\lambda y.$ din expresia în care a fost înlocuit. \\
-Astfel, ​expresia corecta ​ar fi: $\lambda a.(\lambda x.y \ a)$. \\+Astfel, ​reducerea corectă ​ar fi: $\lambda a.(\lambda x.y \ a)$. \\
  
-Pentru a detecta ​si rezolva //variable capture//, o sa pregatim cateva functii ajutatoare: \\+Pentru a detecta ​și rezolva //variable capture//, o să pregătim câteva funcții ajutătoare: \\
 **1.1.** (//5p//) Implementați funcția auxiliară ''​vars''​ care returnează o listă cu toate ''​String''​-urile care reprezintă variabile într-o expresie. **1.1.** (//5p//) Implementați funcția auxiliară ''​vars''​ care returnează o listă cu toate ''​String''​-urile care reprezintă variabile într-o expresie.
 \\ \\
-**1.2.** (//5p//) Implementați funcția auxiliară ''​free_vars''​ care returnează o listă cu toate ''​String''​-urile care reprezintă variabile libere într-o expresie. (**notă**: dacă o variabilă este liberă în expresie în mai multe contexte, o să apară o singură dată în listă). \\ +**1.2.** (//5p//) Implementați funcția auxiliară ''​freeVars''​ care returnează o listă cu toate ''​String''​-urile care reprezintă variabile libere într-o expresie. (**notă**: dacă o variabilă este liberă în expresie în mai multe contexte, o să apară o singură dată în listă). \\ 
-**1.3.** (//10p//) Implementați funcția auxiliară ''​new_vars''​ care primeste ​lista de ''​String''​-uri ​si intoarce cel mai mic ''​String''​ lexicografic care nu apare in lista (**e.g.** ''​new_vars ["​a",​ "​b",​ "​c"​]''​ o sa intoarca ​''"​d"''​).+**1.3.** (//10p//) Implementați funcția auxiliară ''​newVars''​ care primește ​listă ​de ''​String''​-uri ​și intoarce cel mai mic ''​String''​ lexicografic care nu apare în listă ​(**e.g.** ''​new_vars ["​a",​ "​b",​ "​c"​]''​ o să întoarcă ​''"​d"''​).
  
 ---- ----
  
-**1.4.** (//20p//) Implementați funcția ''​reduce''​ care realizeaza ​$\beta$-reducerea unui **redex** luând în considerare și //​**coliziunile de nume**//. Funcția primește **redex**-ul '​deconstruit'​ și returnează expresia rezultată. \\+**1.4.** (//5p//) Implementați funcția ''​isNormalForm''​ care verifică daca o expresie este în formă normală. \\ 
 + 
 +**1.5.** (//20p//) Implementați funcția ''​reduce''​ care realizează ​$\beta$-reducerea unui **redex** luând în considerare și //​**coliziunile de nume**//. Funcția primește **redex**-ul '​deconstruit'​ și returnează expresia rezultată. \\
 <code haskell> <code haskell>
 reduce :: String -> Lambda -> Lambda -> Lambda reduce :: String -> Lambda -> Lambda -> Lambda
 reduce x e_1 e_2 = undefined reduce x e_1 e_2 = undefined
--- oriunde apare variabila x in e_1, este inlocuita ​cu e_2+-- oriunde apare variabila x în e_1, este inlocuită ​cu e_2
 </​code>​ </​code>​
 \\ \\
Line 66: Line 68:
 O să facem reducerea „step by step”, implementăm o funcție care reduce doar următorul **redex** comform unei strategii. Apoi aplicăm acesți pași până expresia rămasă este în formă normală. O să facem reducerea „step by step”, implementăm o funcție care reduce doar următorul **redex** comform unei strategii. Apoi aplicăm acesți pași până expresia rămasă este în formă normală.
 \\ \\
-**1.5.** (//10p//) Implementați funcția ''​normal_step''​ care aplică un pas de reducere după strategia Normală. \\ +**1.6.** (//10p//) Implementați funcția ''​normalStep''​ care aplică un pas de reducere după strategia Normală. \\ 
-**1.6.** (//10p//) Implementați funcția ''​applicative_step''​ care aplică un pas de reducere după strategia Aplicativă. \\ +**1.7.** (//10p//) Implementați funcția ''​applicativeStep''​ care aplică un pas de reducere după strategia Aplicativă. \\ 
-**1.7.** (//5p//) Implementați funcția ''​is_normal_form''​ care verifica daca o expresie este în formă normală. \\ +**1.8.** (//5p//) Implementați funcția ''​simplify'',​ care primeste o funcție ​de step și aplică până expresia rămâne în formă normalăși întoarce ​listă ​cu toți pași intermediari ai reduceri. \\
-**1.8.** (//5p//) Implementați funcția ''​simplify'',​ care primeste o functie ​de step si aplica pana expresie ramane in forma normalasi intoarce ​lista cu toti pasi intermediari ai reduceri. \\+
  
 ===== 2. Parsing ===== ===== 2. Parsing =====
Line 78: Line 79:
 <​code>​ <​code>​
 <​lambda>​ ::= <​variable>​ | '​\'​ <​variable>​ '​.'​ <​lambda>​ | (<​lambda>​ <​lambda>​) <​lambda>​ ::= <​variable>​ | '​\'​ <​variable>​ '​.'​ <​lambda>​ | (<​lambda>​ <​lambda>​)
-<​variable>​ ::= '​a'​ | '​b'​ | '​c'​ | ... | '​z'​+<​variable> ::= <​variable><​alpha>​ | <​alpha>​  
 +<alpha> ::= '​a'​ | '​b'​ | '​c'​ | ... | '​z'​
 </​code>​ </​code>​
 \\ \\
  
-**2.1.** (//40p//) Implementați funcția ''​parse_lambda''​ care parsează un ''​String''​ și returnează o expresie ​SAU o eroare (sub forma de ''​String''​).+**2.1.** (//40p//) Implementați funcția ''​parseLambda''​ care parsează un ''​String''​ și returnează o expresie
  
 <note important>​ <note important>​
Line 103: Line 105:
 ===== 3. Steps towards a programming language ===== ===== 3. Steps towards a programming language =====
  
-Teoretic, folosind ​parserul și evaluatorul anterior, putem să evaluăm orice rezultat computabil, expresiile lambda fiind suficient de expresive, însă este foarte greu să scrii astfel de expresii. Pentru a fi mai ușor de folosit, vrem să introducem noțiunea de variabile. Pentru asta o să folosim conceptul de **macro**. Primul pas ar fi să extindem definiția unei expresii cu un constructor ''​Macro''​ care acceptă un ''​String''​ ca parametru (denumirea macro-ului). +Folosind ​parserul și evaluatorul anterior, putem să evaluăm orice rezultat computabil, expresiile lambda fiind suficient de expresive, însă, cum probabil ați văzut la curs și laborator, ​este foarte greu să scrii astfel de expresii. Pentru a fi mai ușor de folosit, vrem să putem denumi anumite sub-expresii pentru a le putea refolosi ulterior. Pentru asta o să folosim conceptul de **macro**. Primul pas ar fi să extindem definiția unei expresii cu un constructor ''​Macro''​ care acceptă un ''​String''​ ca parametru (denumirea macro-ului). ​O să introducem ​și sintaxa: orice șir de caractere format numai din litere mari ale alfabetului englez si cifre e considerat un macro.
- +
-Pentru a folosi un macro, ​introducem sintaxa: orice șir de caractere format numai din litere mari ale alfabetului englez si cifre e considerat un macro.+
  
 Câteva exemple de expresii cu macro-uri sunt: Câteva exemple de expresii cu macro-uri sunt:
Line 113: Line 113:
 $ \lambda x.(NOT \ \lambda y.AND) $ \\ $ \lambda x.(NOT \ \lambda y.AND) $ \\
  
-Pentru a evalua o expresie cu macro-uri, introducem noțiunea de //**context computațional**//​. Contextul în care evaluăm o expresie este pur și simplu un dicționar de nume de macro-uri și expresii pe care aceste nume le înlocuiesc. Astfel când evaluăm un macro, facem pur și simpu substituție textuală cu expresia găsită în dicționar.+Pentru a putea folosi ​macro-uri, ​trebuie să introducem noțiunea de //**context computațional**//​. Contextul în care evaluăm o expresie este pur și simplu un dicționar de nume de macro-uri și expresii pe care aceste nume le înlocuiesc. Astfel când evaluăm un macro, facem pur și simpu substituție textuală cu expresia găsită în dicționar.
  
-**3.1.** (//10p//) Implementați funcția ''​replace_macros''​ care ia un context și o expresie care poate să conțină macro-uri, ​și întoarce expresia după evaluarea tuturor ​macro-urilor ​SAU o eroare ​in cazul in care o variabila ​nu a fost gasita (expresia ​returnata ar trebui sa nu mai contina macro-uri, ca sa putem folosi ​''​simplify'' ​implementat anterior).+În cazul în care nu găsim macro-ul în context, nu o să știm cum să evaluăm expresia, asa că am vrea să întoarcem o eroare. O să extindem tipul de date întors la ''​Either String [Lambda]''​ și o să întoarce ''​Left''​ în caz de eroare și ''​Right''​ în cazul în care evaluarea se termina cu succes. 
 + 
 +**3.1.** (//15p//) Implementați funcția ''​simplifyCtx''​ care ia un context și o expresie care poate să conțină macro-uri, ​face substituțiile ​macro-urilor ​(sau returnează ​eroare ​dacă nu reușeste) și evaluează ​expresia ​rezultată folosind strategia de step primită. (**Hint:​** ​putem refolosi ​''​simplify'' ​ca să nu rescriem logica?)
  
 <note info> <note info>
-Codul atunci ​cand lucrezi cu ''​Maybe''​ sau ''​Either'' ​poata sa devina complicat ​atunci cand faci ''​case''​ pe fiecare variabila sa verifici erorilede asta exista o monada definita atat peste tipul de date ''​Maybe'' ​cat si peste ''​Either'', ​foloseste ​''​do''​ notation ​sa iti usurezi viata.+Codul atunci ​când lucrezi cu ''​Maybe''​ sau ''​Either'' ​poate să devina complicat ​dacă folosim ​''​case''​-uri pe toate variabilelepentru a ușura lucrul cu ele există monade definite atât peste tipul de date ''​Maybe'' ​cât și peste ''​Either'', ​poți folosi ​''​do''​ notation ​să îți ușurezi viața.
 </​note>​ </​note>​
  
Line 125: Line 127:
 </​note>​ </​note>​
  
-Ca sa ne folosim ​de macro-uri ​ne trebuie si metoda ​de a le defini. Pentru asta o sa definim conceptul de linie de cod:+Ultimul pas ca să ne putem folosi ​de macro-uri ​e să găsim ​metodă ​de a le defini. Pentru asta o sa definim conceptul de linie de cod:
 <code haskell> <code haskell>
-data Code Code Lambda +data Line Eval Lambda 
-          | Assign ​String Lambda+          | Binding ​String Lambda
 </​code>​ </​code>​
-O linie de cod poate sa fie ori o expresie lambda, ori o definitie ​de macro. Astfel daca o sa evaluam mai multe linii de cod, in expresii o sa ne putem folosi de macro-urile definite anterior.+O linie de cod poate să fie ori o expresie lambda, ori o definiție ​de macro. Astfel daca o sa evaluam mai multe linii de cod, în expresii o sa ne putem folosi de macro-urile definite anterior.
  
 **3.2.** (//5p//) Modificați parser-ul vostru astfel încât să parsați și expresii care conțin macro-uri. **3.2.** (//5p//) Modificați parser-ul vostru astfel încât să parsați și expresii care conțin macro-uri.
  
-**3.3.** (//5p//) Implementați funcția ''​parse_code''​ care să parseze o linie de cod, daca gaseste ​erori o sa intoarca ​o eroare (sub forma de ''​String''​).+**3.3.** (//5p//) Implementați funcția ''​parseLine''​ care să parseze o linie de cod, dacă găsește ​erori o să întoarcă ​o eroare (sub formă ​de ''​String''​).
  
 ===== 4.Default Library ===== ===== 4.Default Library =====
  
-Acum ca avem un interpretor ​functional ​pentru calcul lambda, hai sa definim ​si cateva ​expresii uzuale, ca sa le putem folosi ca un context default pentru interpretorul nostru.+Acum că avem un interpretor ​funcțional ​pentru calcul lambda, hai să definim ​și câteva ​expresii uzuale, ca să le putem folosi ca un context default pentru interpretorul nostru ​(un fel de standard library).
  
-In fisierul ​''​Default.hs''​ sunt deja definiti ​cativa ​combinatori. ​Hai sa definim si alte lucruri extra.+În fișierul ​''​Default.hs''​ sunt deja definiti ​câțiva ​combinatori. ​Definiții restul expresiilor.
  
-**4.1.** (//5p//) Definiti ​ca expresii ​Lambda cateva ​macro-uri utile pentru lucrul cu Booleene (''​TRUE'',​ ''​FALSE'',​ ''​AND'',​ ''​OR'',​ ''​NOT'',​ ''​XOR''​).+**4.1.** (//6p//) Definiți ​ca expresii ​lambda câteva ​macro-uri utile pentru lucrul cu Booleene (''​TRUE'',​ ''​FALSE'',​ ''​AND'',​ ''​OR'',​ ''​NOT'',​ ''​XOR''​).
  
-**4.2.** (//5p//) Definiti ​ca expresii ​Lambda cateva ​macro-uri utile pentru lucrul cu perechi (''​PAIR'',​ ''​FIRST'',​ ''​SECOND''​).+**4.2.** (//4p//) Definiți ​ca expresii ​lambda câteva ​macro-uri utile pentru lucrul cu perechi (''​PAIR'',​ ''​FIRST'',​ ''​SECOND''​).
  
-**4.3.** (//10p//) Definiti ca expresii ​Lambda cateva ​macro-uri utile pentru lucrul cu numere naturale (''​N0'',​ ''​N1'',​ ''​N2'',​ ''​SUCC'',​ ''​PRED'',​ ''​ADD'',​ ''​SUB'',​ ''​MULT''​).+**4.3.** (//5p//) Definiti ca expresii ​lambda câteva ​macro-uri utile pentru lucrul cu numere naturale (''​N0'',​ ''​N1'',​ ''​N2'',​ ''​SUCC'',​ ''​PRED'',​ ''​ADD'',​ ''​SUB'',​ ''​MULT''​).
  
 <​note>​ <​note>​
-Pentru a rezolva cerinta ​**4** este nevoie ca cerinta ​**1** sa fie completa, pentru ca o sa ne folosim de ''​simplify''​ implementat de voi sa testam ​expresiile, deoarece vrem sa testam ​comportamentul lor, nu structura.+Pentru a fi punctați pentru cerința ​**4** este nevoie ca cerința ​**1** sa fie completată, pentru ca o sa ne folosim de ''​simplify''​ implementat de voi să testăm ​expresiile, deoarece vrem să testăm ​comportamentul lor, nu structura. 
 </​note>​ </​note>​
  
 ===== REPL ===== ===== REPL =====
  
-La finalul temei, ​o să puteți ​să rulați ''​runhaskell main.hs''​ pentru a porni un **REPL**care se folosește de funcțiile și parserul făcute de voi. În acesta ​puteți ​să evaluațdiverse expresii lambdacum fost prezentat anterior.+La finalul temei, puteți rula ''​runhaskell main.hs''​ pentru a vedea aplicația creată de voi :). O să pornească ​un **REPL** ​în care puteți scrie expresii lambda pentru a le evalua (main-ul ​se folosește de evaluarea normală implementată de voi), puteți ​crea binding-uri noi sau folosi binding-uri din contextul default creat. 
 + 
 +Există șcâteva comenzi utile: 
 +  * '':​q''​ - pentru a ieși din **REPL** 
 +  * '':​r''​ - pentru a sterge contextulreluând contextul default 
 +  * '':​ctx''​ - pentru ​afișa contextul curent
  
 ===== Punctare ===== ===== Punctare =====
Line 162: Line 170:
     * 5p - **1.2.** - aflarea variabilelor libere     * 5p - **1.2.** - aflarea variabilelor libere
     * 10p - **1.3.** - generarea unei noi variabile     * 10p - **1.3.** - generarea unei noi variabile
-    * 20p - **1.4.** - reducerea unui redex +    * 5p - **1.4.** - verificarea formei normale 
-    * 10p - **1.5.** - step normal +    * 20p - **1.5.** - reducerea unui redex 
-    * 10p - **1.6.** - step aplicativ +    * 10p - **1.6.** - step normal 
-    * 5p - **1.7.** - verificarea formei normale+    * 10p - **1.7.** - step aplicativ
     * 5p - **1.8.** - reducerea unei expresii step by step     * 5p - **1.8.** - reducerea unei expresii step by step
   - Parsing   - Parsing
     * 40p - **2.1.** parsare     * 40p - **2.1.** parsare
   - Steps towards a programming language   - Steps towards a programming language
-    * 10p - **3.1.** evaluarea ​unui macro+    * 15p - **3.1.** evaluarea ​unei expresii cu macro-uri
     * 5p - **3.2.** parsarea expresiilor cu macro-uri     * 5p - **3.2.** parsarea expresiilor cu macro-uri
     * 5p - **3.3.** parsarea liniilor de cod     * 5p - **3.3.** parsarea liniilor de cod
   - Code   - Code
-    * 5p - **4.1.** expresii boolene +    * 6p - **4.1.** expresii boolene 
-    * 5p - **4.2.** expresii perechi +    * 4p - **4.2.** expresii perechi 
-    * 10p - **4.2.** expresii numere naturale+    * 5p - **4.2.** expresii numere naturale
  
 După cum s-a anunțat la începutul semestrului,​ pentru studenții care au punctaj maxim pe toate 3 temele de pe parcursul semestrului,​ o să se echivaleze examenul din sesiune cu punctaj maxim. După cum s-a anunțat la începutul semestrului,​ pentru studenții care au punctaj maxim pe toate 3 temele de pe parcursul semestrului,​ o să se echivaleze examenul din sesiune cu punctaj maxim.