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:2026:haskell:t02 [2026/05/11 18:55]
tpruteanu
pp:2026:haskell:t02 [2026/05/11 23:20] (current)
tpruteanu
Line 2: Line 2:
  
 <​note>​ <​note>​
-Schelet: {{:pp:2024:lambda-interpreter.zip|}}+Schelet: {{:pp:2026:haskell:​skel.zip|}}
 </​note>​ </​note>​
  
 <note warning> <note warning>
-**Deadline:​** ​luni XX mai, ora 23:59 +**Deadline:​** ​duminica 31 mai, ora 23:59 
-  * Temele trebuie submise pe [[curs.upb.ro]],​ în assignment-ul ''​Tema 2''​. +  * Temele trebuie submise pe [[https://curs.upb.ro/​2025/​mod/​assign/​view.php?​id=178980&​forceview=1 | Moodle ​]], în assignment-ul ''​Tema 2''​. 
-  * Pentru întrebări folosiți forum-ul dedicat de pe [[curs.upb.ro]].+  * Pentru întrebări folosiți forum-ul dedicat de pe [[https://curs.upb.ro/​2025/​mod/​forum/​view.php?​id=178978 | Moodle ​]].
 </​note>​ </​note>​
  
Line 47: Line 47:
  
 Pentru a detecta și rezolva //variable capture//, o să pregătim câteva funcții ajutătoare:​ \\ 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.** (//2.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ă ''​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.2.** (//3p//) 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ă ''​newVar''​ care primește o listă de ''​String''​-uri și intoarce cel mai mic ''​String''​ lexicografic care nu apare în listă (**e.g.** ''​newVar ["​a",​ "​b",​ "​c"​]''​ o să întoarcă ''"​d"''​).+**1.3.** (//7p//) Implementați funcția auxiliară ''​newVar''​ care primește o listă de ''​String''​-uri și intoarce cel mai mic ''​String''​ lexicografic care nu apare în listă (**e.g.** ''​newVar ["​a",​ "​b",​ "​c"​]''​ o să întoarcă ''"​d"''​).
  
 ---- ----
  
-**1.4.** (//5p//) Implementați funcția ''​isNormalForm''​ care verifică daca o expresie este în formă normală. \\+**1.4.** (//3p//) 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ă. \\+**1.5.** (//11p//) 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
Line 68: 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.6.** (//10p//) Implementați funcția ''​normalStep''​ care aplică un pas de reducere după strategia Normală. \\ +**1.6.** (//5p//) Implementați funcția ''​normalStep''​ care aplică un pas de reducere după strategia Normală. \\ 
-**1.7.** (//10p//) Implementați funcția ''​applicativeStep''​ care aplică un pas de reducere după strategia Aplicativă. \\ +**1.7.** (//5p//) Implementați funcția ''​applicativeStep''​ care aplică un pas de reducere după strategia Aplicativă. \\ 
-**1.8.** (//5p//) Implementați funcția ''​simplify'',​ care primeste o funcție de step și o aplică până expresia rămâne în formă normală, și întoarce o listă cu toți pași intermediari ai reduceri. \\+**1.8.** (//3.5p//) Implementați funcția ''​simplify'',​ care primeste o funcție de step și o aplică până expresia rămâne în formă normală, și întoarce o listă cu toți pași intermediari ai reduceri. \\
  
 ===== 2. Parsing ===== ===== 2. Parsing =====
Line 95: Line 95:
 \\ \\
  
-**2.1.** (//40p//) Implementați funcția ''​parseLambda''​ care parsează un ''​String''​ și returnează o expresie+**2.1.** (//20p//) Implementați funcția ''​parseLambda''​ care parsează un ''​String''​ și returnează o expresie
  
 <note important>​ <note important>​
Line 128: Line 128:
 Î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. Î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?)+**3.1.** (//14p//) 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>
Line 145: Line 145:
 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. 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.** (//3p//) 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 ''​parseLine''​ care să parseze o linie de cod, dacă găsește erori o să întoarcă o eroare (sub formă de ''​String''​).+**3.3.** (//3p//) 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. De Bruijn =====
- +
-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). +
- +
-În fișierul ''​Default.hs''​ sunt deja definiti câțiva combinatori. Definiții restul expresiilor. +
- +
-**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.** (//4p//) Definiți ca expresii lambda câteva macro-uri utile pentru lucrul cu perechi (''​PAIR'',​ ''​FIRST'',​ ''​SECOND''​). +
- +
-**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>​ +
-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>​ +
- +
-===== 5. De Bruijn =====+
  
 Lucrul cu nume de variabile face $\beta$-reducerea complicată:​ trebuie să detectăm //variable capture// și să generăm nume noi (vezi ''​newVar''​). //De Bruijn indices// elimină complet problema: fiecare variabilă legată e înlocuită cu un număr care indică **câte $\lambda$-uri trebuie urcate până la binder-ul ei**. Două expresii $\alpha$-echivalente devin astfel identice sintactic. Lucrul cu nume de variabile face $\beta$-reducerea complicată:​ trebuie să detectăm //variable capture// și să generăm nume noi (vezi ''​newVar''​). //De Bruijn indices// elimină complet problema: fiecare variabilă legată e înlocuită cu un număr care indică **câte $\lambda$-uri trebuie urcate până la binder-ul ei**. Două expresii $\alpha$-echivalente devin astfel identice sintactic.
Line 185: Line 168:
 ''​DBAbs''​ păstrează numele original al variabilei pe care a legat-o — este doar un //hint// pentru conversia înapoi spre reprezentarea cu nume, și **nu** este luat în considerare la egalitatea structurală (vezi instanța ''​Eq''​ din schelet). ''​DBAbs''​ păstrează numele original al variabilei pe care a legat-o — este doar un //hint// pentru conversia înapoi spre reprezentarea cu nume, și **nu** este luat în considerare la egalitatea structurală (vezi instanța ''​Eq''​ din schelet).
  
-**5.1.** (//8p//) Implementați funcția ''​toDB''​ care convertește o expresie ''​Lambda''​ la reprezentarea De Bruijn. Funcția primește și un context (o listă de nume care reprezintă binder-ele active, de la cel mai interior la cel mai exterior). Macro-urile se tratează ca variabile libere.+**4.1. / 4.2.** (//7p//) Implementați funcțiile ''​toDB''​ care convertește o expresie ''​Lambda''​ la reprezentarea De Bruijn. Funcția primește și un context (o listă de nume care reprezintă binder-ele active, de la cel mai interior la cel mai exterior) ​si ''​fromDB''​ care convertește înapoi de la De Bruijn la ''​Lambda'',​ folosind contextul pentru a reconstrui numele variabilelor legate. Macro-urile se tratează ca variabile libere.
 <code haskell> <code haskell>
 toDB :: Context -> Lambda -> DeBruijn toDB :: Context -> Lambda -> DeBruijn
-</​code>​ 
- 
-**5.2.** (//5p//) Implementați funcția ''​fromDB''​ care convertește înapoi de la De Bruijn la ''​Lambda'',​ folosind contextul pentru a reconstrui numele variabilelor legate. 
-<code haskell> 
 fromDB :: Context -> DeBruijn -> Lambda fromDB :: Context -> DeBruijn -> Lambda
 </​code>​ </​code>​
  
-**5.3.** (//5p//) Implementați funcția ''​isNormalForm''​ peste ''​DeBruijn''​ care verifică dacă o expresie este în formă normală.+**4.3.** (//2.5p//) Implementați funcția ''​isNormalForm''​ peste ''​DeBruijn''​ care verifică dacă o expresie este în formă normală.
  
-**5.4.** (//10p//) Implementați funcția ''​reduce''​ care realizează un pas de $\beta$-reducere peste reprezentarea De Bruijn. Spre deosebire de varianta cu nume, **nu** mai este nevoie de detecția //variable capture//, în schimb trebuie să tratați corect //​shifting-ul//​ indecșilor:​ atunci când coborâți într-un ''​DBAbs'',​ indecșii liberi din valoarea substituită cresc cu 1.+**4.4.** (//3.5p//) Implementați funcția ''​reduce''​ care realizează un pas de $\beta$-reducere peste reprezentarea De Bruijn. Spre deosebire de varianta cu nume, **nu** mai este nevoie de detecția //variable capture//, în schimb trebuie să tratați corect //​shifting-ul//​ indecșilor:​ atunci când coborâți într-un ''​DBAbs'',​ indecșii liberi din valoarea substituită cresc cu 1.
 <code haskell> <code haskell>
 reduce :: DeBruijn -> DeBruijn -> DeBruijn reduce :: DeBruijn -> DeBruijn -> DeBruijn
Line 203: Line 182:
 </​code>​ </​code>​
  
-**5.5.** (//5p//) Implementați funcția ''​normalStep''​ (strategia normală) peste ''​DeBruijn''​+**4.5. / 4.6.** (//4.5p//) Implementați funcțiile ''​normalStep''​ (strategia normală) peste ''​DeBruijn'' ​si ''​applicativeStep''​ (strategia aplicativă) peste ''​DeBruijn''​.
- +
-**5.6.** (//5p//) Implementați funcția ​''​applicativeStep''​ (strategia aplicativă) peste ''​DeBruijn''​.+
  
-**5.7.** (//2p//) Implementați funcția ''​simplify''​ care aplică pași de reducere până la forma normală, analog cu cea din cerința **1.8**.+**4.7.** (//2.5p//) Implementați funcția ''​simplify''​ care aplică pași de reducere până la forma normală, analog cu cea din cerința **1.8**.
  
 <note tip> <note tip>
Line 223: Line 200:
  
 ===== Punctare ===== ===== Punctare =====
-Tema are un punctaj total de **1p** din nota finală, împărțit pe subpuncte:​ +Tema are un punctaj total de **0.5p** din nota finală, împărțit pe subpuncte:​ 
-  - Evaluation +  - Evaluation - 40p 
-    * 5p **1.1.** - aflarea variabilelor +  - Parsing - 20p 
-    * 5p - **1.2.** - aflarea variabilelor libere +  - Steps towards a programming language - 20p 
-    * 10p - **1.3.** - generarea unei noi variabile +  - De Bruijn - 20p
-    * 5p - **1.4.** - verificarea formei normale +
-    * 20p - **1.5.** - reducerea unui redex +
-    * 10p - **1.6.** - step normal +
-    * 10p - **1.7.** - step aplicativ +
-    * 5p - **1.8.** - reducerea unei expresii step by step +
-  - Parsing +
-    * 40p **2.1.** parsare +
-  - Steps towards a programming language +
-    * 15p **3.1.** evaluarea unei expresii cu macro-uri +
-    * 5p - **3.2.** parsarea expresiilor cu macro-uri +
-    * 5p - **3.3.** parsarea liniilor de cod +
-  - Default Library +
-    * 6p - **4.1.** expresii boolene +
-    * 4p - **4.2.** expresii perechi +
-    * 5p - **4.3.** expresii numere naturale +
-  - De Bruijn +
-    * 8p **5.1.** ''​toDB''​ +
-    * 5p - **5.2.** ''​fromDB''​ +
-    * 5p - **5.3.** ''​isNormalForm''​ +
-    * 10p - **5.4.** ''​reduce''​ +
-    * 5p - **5.5.** ''​normalStep''​ +
-    * 5p - **5.6.** ''​applicativeStep''​ +
-    * 2p - **5.7.** ''​simplify''​+
  
-Totalul de **190p** o sa fie scalat la **1p**.+Totalul de **100p** o sa fie scalat la **0.5p**.
  
 După cum s-a anunțat la începutul semestrului,​ pentru studenții care au punctaj maxim pe cele 2 teme 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 cele 2 teme de pe parcursul semestrului,​ o să se echivaleze examenul din sesiune cu punctaj maxim.
  
 <note warning> <note warning>
-Pot să existe depunctări de până la **1p** pentru implementări hardcodate sau plagiat.+Pot să existe depunctări de până la **0.5p** pentru implementări hardcodate sau plagiat.
 </​note>​ </​note>​