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/04/20 12:07]
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 ​un macro, pentru ​cerintele ​**1** si **2** il puteti ​ignora, 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 ​variabile ​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 =====
- 
-Glosar de termeni: 
-  * //​$\beta$-reducere//​ - //​reducere//​ a unei lambda-expresii,​ in sensul in care a fost prezentat la curs. 
-  * **redex** - lambda-expresie de forma $( \lambda x.e_1 \ e_2 )$. 
  
 <​note>​ <​note>​
-Înainte de a reduce o expresie (realizarea $\beta$-reducerii),​ trebuie să rezolvăm //**coliziunile de nume**//. \\ +**Reminder** 
-Dacă am încerca să reducem un **redex** fără a face substituții textuale (un **redex** ​o expresie reductibilă,​ **i.e.** are forma $( \lambda x.e_1 \ e_2 $) există riscul de a pierde întelesul original al expresiei. \\ +  * **redex** ​o expresie reductibilă,​ **i.e.** are forma $( \lambda x.e_1 \ e_2 $) 
-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. \\ +  * **normal-form** - expresie care nu mai poate fi redusa ​(nu contine niciun ​**redex**)
-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)$. \\+
 </​note>​ </​note>​
  
-Pentru a detecta ​si rezolva //variable capture//, o sa pregatim cateva functii ajutatoare: \\+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 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. \\ 
 +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. \\ 
 +Astfel, reducerea corectă ar fi: $\lambda a.(\lambda x.y \ a)$. \\ 
 + 
 +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 reduce un **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 variabile ​in e_1, este inlocuita ​cu e_2+-- oriunde apare variabila ​în e_1, este inlocuită ​cu e_2
 </​code>​ </​code>​
 \\ \\
Line 64: 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 =====
  
-Momentan putem să evaluăm expresii ​care le definim ​tot noi sub formă de cod, pentru ​a avea un interpretor funcțional,​ trebuie să putem lua expresii sub forma de șiruri de caractere și să le transformăm în **TDA**-uri (acest proces se numește **parsare**). \\+Momentan putem să evaluăm expresii ​definite ​tot de noi sub formă de cod. Pentru ​a avea un interpretor funcțional,​ trebuie să putem lua expresii sub forma de șiruri de caractere și să le transformăm în **TDA**-uri (acest proces se numește **parsare**). \\
  
 O gramatică pentru expresii lambda ar putea fi: \\ O gramatică pentru expresii lambda ar putea fi: \\
 <​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.** (//50p//) 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 101: 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 111: 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 123: 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 160: 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
-    * 50p - **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 ​pt 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.
Line 184: Line 194:
 ===== Testing ===== ===== Testing =====
  
-Pentru testare puteți rula un set de teste unitare cu ''​runhaskell test.hs''​. Pentru a testa doar o cerință, puteți da unul din argumentele [lambda | parser | code | default] pentru a rula cerințele 1, 2, 3 sau 4.+Pentru testare puteți rula un set de teste unitare cu ''​runhaskell test.hs''​. Pentru a testa doar o cerință, puteți da unul din argumentele [lambda | parser | binding ​| default] pentru a rula testele doar pentru ​cerinț1, 2, 3 sau 4.
  
 Pentru fiecare test v-a aparea **PASSED** / **FAILED**, și în caz de **FAILED**, diferențele între rezultatul vostru și cel dorit. Pentru fiecare test v-a aparea **PASSED** / **FAILED**, și în caz de **FAILED**, diferențele între rezultatul vostru și cel dorit.
Line 196: Line 206:
 Temele trebuie submise pe curs.upb.ro,​ în assignment-ul ''​Tema 3''​. Temele trebuie submise pe curs.upb.ro,​ în assignment-ul ''​Tema 3''​.
  
-În arhivă trebuie să se regăsească:​ +În arhivă trebuie să se regăsească ​//cel puțin//
-  * Code.hs +  * ''​Lambda.hs''​ 
-  * Lambda.hs +  * ''​Parser.hs''​ 
-  * Parser.hs +  * ''​Binding.hs''​ 
-  * <alte fisiere>.hs +  * ''​ID.txt'' ​- acest fișier ​va conține ​singură ​linie, ​formată ​din ID-ul unic al fiecărui ​student
-  * ID.txt - acest fisier ​va contine ​singura ​linie, ​formata ​din ID-ul unic al fiecarui ​student+