This shows you the differences between two versions of the page.
pp:21:teme:racket-teste-enunt [2021/03/18 18:42] mihaela.balint |
pp:21:teme:racket-teste-enunt [2021/04/06 22:45] (current) mihaela.balint [Depunctări] |
||
---|---|---|---|
Line 1: | Line 1: | ||
- | ===== Etapa 3 ===== | + | ===== Corectare Tema 1 ===== |
- | Această etapă își propune să sublinieze importanța abstractizării. Va trebui să vă definiți propriul TDA (tip de date abstract) și să oferiți o interfață completă (un set de constructori și operatori) prin care utilizatorul poate manipula valorile tipului, independent de implementarea din spate. Apoi, este esențial ca voi înșivă să folosiți TDA-ul doar prin intermediul interfeței (în etapa 4 veți înțelege și mai bine de ce este esențial). | + | ==== Depunctări ==== |
- | + | De marcat în spreadsheet, doar dacă ceva este în neregulă, următoarele rubrici: | |
- | Veți începe rezolvarea etapei prin a implementa TDA-ul ''%%queue%%'' în fișierul **queue.rkt**. | + | * (generic) **efecte laterale** ------ **1** dacă folosește funcții cu efecte laterale |
- | + | * (generic) **checker tricks** ------ **numele funcțiilor** care sunt inginerite astfel încât să treacă mai multe teste decât ar trebui | |
- | Acest tip reprezintă o coadă (first-in-first-out) ca pe o structură: | + | * (etapa 2) **funcții curry** ------ **un număr între 1 și 3**, în funcție de câte dintre tt+, et+, add-to-counter nu sunt implementate în formă curry |
- | <code lisp> | + | * (etapa 2) **lipsă abstractizare** ------ **1** dacă min-tt și min-et nu sunt derivate dintr-o funcție mai abstractă, evitând rescrierea aceluiași cod |
- | (define-struct queue (left right size-l size-r)) | + | * (etapa 3) **incorect TDA** ------ **1** dacă TDA-ul queue nu este folosit doar prin intermediul interfeței sale |
- | </code> | + | * (etapa 4) **fluxuri ineficiente** ------ **un număr între 1 și 3**, în funcție de câte dintre rotate, enqueue, dequeue trec testele fără a fi implementate eficient (conform indicațiilor); numărați funcția doar dacă sursa ineficienței este în funcția respectivă; ex: dacă enqueue și dequeue sunt ineficiente din cauză că folosesc un rotate ineficient, atunci scrieți 1, nu 3) |
- | * left, right | + | |
- | * sunt stive (last-in-first-out, implementate ca liste Racket) | + | |
- | * fiecare adăugare în coadă va fi o adăugare în stiva right | + | |
- | * ex adăugare: \\ adaug 1 => ''%%right = '(1)%%'', \\ adaug 2 => ''%%right = '(2 1)%%'' | + | |
- | * fiecare scoatere din coadă va fi o scoatere din stiva left (când left este vidă, va trebui mai întâi să mutăm toate elementele din right în left, apoi să scoatem din left) | + | |
- | * mutarea este rezultatul unor operații pop (din right) + push (în left) repetate | + | |
- | * ex mutare: \\ mut în ''%%left = '()%%'' din ''%%right = '(2 1)%%'' => \\ ''%%left = '(2)%%'', ''%%right = '(1)%%'' (primul pop din right îl extrage pe 2 și îi face push în left) => \\ ''%%left = '(1 2)%%'', ''%%right = '()%%'' (apoi pop din right îl extrage pe 1 și îi face push în left) | + | |
- | * ex scoatere: \\ scot din coada cu ''%%left = '()%%'', ''%%right = '(2 1)%%'' => \\ ''%%left = '(1 2)%%'', ''%%right = '()%%'' (după mutarea elementelor) => \\ ''%%left = '(2)%%'', ''%%right = '()%%'' (după scoaterea primului element) | + | |
- | * observați că primul element adăugat este primul element scos (first-in-first-out) | + | |
- | * size-l, size-r | + | |
- | * sunt numere naturale, reprezentând numărul de elemente din cele 2 stive | + | |
- | + | ||
- | Sarcina voastră este să implementați interfața TDA-ului queue: | + | |
- | <file> | + | |
- | empty-queue : -> queue (constructor nular pentru o coadă goală) | + | |
- | queue-empty? : queue -> Bool (operator care verifică dacă o coadă este goală) | + | |
- | enqueue : Elem x queue -> queue (operatorul de adăugare în coadă) | + | |
- | dequeue : queue -> queue (operatorul de scoatere din coadă) | + | |
- | top : queue -> Elem (operatorul de vizualizare a elementului din vârful cozii) | + | |
- | </file> | + | |
| | ||
- | Această reprezentare pentru coadă asigură cost amortizat O(1) pentru operațiile de enqueue și dequeue. Vom folosi această reprezentare pentru câmpul queue al structurii counter, întrucât este mai eficientă decât reprezentarea cu liste Racket din etapele 1 și 2. | + | ==== Sugestii de întrebări la prezentare ==== |
- | + | * (etapa 1) | |
- | După ce ați finalizat implementarea TDA-ului, continuați dezvoltarea simulatorului în fișierul **supermarket.rkt**. | + | * cum alegem casa la care așezăm un client |
- | + | * cum se tratează întârzierile la casele fără clienți | |
- | În primul rând, va trebui să adaptați o serie de funcții de la etapa 2 astfel încât ele să țină cont de noua reprezentare (în care câmpul queue din structura counter este de tip coadă (queue) - TDA-ul implementat de voi; este o coincidență că numele câmpului coincide cu numele tipului, în niciun caz nu era necesar acest lucru). | + | * (etapa 2) |
- | + | * unde exploatăm faptul că am definit funcții curry | |
- | În plus față de etapa anterioară, în această etapă simulatorul trebuie să modeleze trecerea timpului. Până acum, simulatorul trata așezările la cozi, întârzierile și deschiderile de noi case ca și cum s-ar produce în ordine, dar la un același moment de timp. Acest lucru nu corespunde realității - între diversele evenimente este firesc să treacă timp, timp în care clienții avansează la case și, la un moment dat, părăsesc supermarketul. | + | * cum determinăm câte case noi trebuie deschise și care sunt indecșii acestora |
- | + | * cum este folosit remove-first-from-counter | |
- | Exceptând adaptările menționate, funcțiile principale pe care va trebui să le implementați sunt: | + | * (etapa 3) |
- | <file> | + | * cum tratăm cazul în care în numărul dat de minute ies mai mulți clienți (de la aceeași casă / de la case diferite) |
- | (pass-time-through-counter minutes) | + | * cum ordonăm clienții care ies simultan |
- | </file> | + | * de ce este implementată coada cu 2 stive |
- | * este o funcție curry (aplicată doar pe un număr de minute, va aștepta un al doilea argument de tip counter) | + | * (etapa 4) |
- | * odată ce și-a primit (pe rând) argumentele, pass-time-through-counter actualizează tt-ul și et-ul casei în tt-ul și et-ul pe care casa ar trebui să le aibă după trecerea numărului dat de minute | + | * ce operație pe coadă optimizăm și cum |
- | * queue-ul casei nu se modifică, pentru că intenția este de a nu folosi niciodată această funcție pentru a avansa cu un număr de minute mai mare decât timpul până la ieșirea primului client din coadă | + | * s-a modificat în vreun fel structura counter |
- | + | * ce se întâmplă cu clienții de la casele care se închid | |
- | Exemplu: | + | * (generic) |
- | <code lisp> | + | * ce se schimbă de la o etapă la alta |
- | ((pass-time-through-counter 5) | + | * câte moduri diferite de a reprezenta coada de clienți s-au folosit în cele 4 etape |
- | (counter 1 | + | * care sunt situațiile tratate de funcția serve |
- | 12 | + | * unde s-au putut / s-ar fi putut folosi funcționale |
- | 7 | + | |
- | (make-queue '() '((ada . 7)) 0 1))) | + | |
- | </code> | + | |
- | => | + | |
- | ''%%(counter 1 7 2 (queue '() '((ada . 7)) 0 1))%%'' | + | |
- | + | ||
- | <file> | + | |
- | (serve requests fast-counters slow-counters) | + | |
- | </file> | + | |
- | * serve actualizează casele din fast-counters și slow-counters pe măsură ce situația lor evoluează, pe baza listei ''%%requests%%'' în care elementele sunt: | + | |
- | * cereri (așezări la coadă, întârzieri, ajustări ale numărului de case) \\ sau | + | |
- | * timpi care trec între cereri | + | |
- | + | ||
- | Exemplu: | + | |
- | <code lisp> | + | |
- | (serve '((ana 14) (mia 2) 5 (ion 7) (delay 1 2) 7) | + | |
- | (list (empty-counter 1)) | + | |
- | (list (empty-counter 2) (empty-counter 3))) | + | |
- | </code> pentru ITEMS = 5: | + | |
- | * observăm că avem o casă fast (o vom numi C1) și 2 case slow (le vom numi C2 și C3) | + | |
- | * primele 2 cereri distribuie cei 2 clienți astfel: | + | |
- | * ana la C2 => ''%%C2 = (counter 2 14 14 (queue '() '((ana . 14)) 0 1))%%'' | + | |
- | * mia la C1 => ''%%C1 = (counter 1 2 2 (queue '() '((mia . 2)) 0 1))%%'' | + | |
- | * apoi trec 5 minute, după care situația trebuie să fie: | + | |
- | * mia a ieșit de la C1, care a rămas goală => ''%%C1 = (counter 1 0 0 (queue '() '() 0 0))%%'' | + | |
- | * la C2 au trecut 5 minute => ''%%C2 = (counter 2 9 9 (queue '() '((ana . 14)) 0 1))%%'' | + | |
- | * C3 a rămas cum era: goală și neîntârziată => ''%%C3 = (counter 3 0 0 (queue '() '() 0 0))%%'' | + | |
- | * au părăsit supermarketul, în ordine: ''%%'((1 . mia))%%'' (mia de la C1) | + | |
- | * ion se așază la C3 => ''%%C3 = (counter 3 7 7 (queue '() '((ion . 7)) 0 1))%%'' | + | |
- | * C1 este întârziată cu 2 minute => ''%%C1 = (counter 1 2 2 (queue '() '() 0 0))%%'' | + | |
- | * apoi trec 7 minute, după care situația trebuie să fie: | + | |
- | * întârzierea de la C1 s-a consumat => ''%%C1 = (counter 1 0 0 (queue '() '() 0 0))%%'' | + | |
- | * la C2 au trecut 7 minute => ''%%C2 = (counter 2 2 2 (queue '() '((ana . 14)) 0 1))%%'' | + | |
- | * ion a ieșit de la C3, care a rămas goală => ''%%C3 = (counter 3 0 0 (queue '() '() 0 0))%%'' | + | |
- | * au părăsit supermarketul, în ordine:: ''%%'((1 . mia) (3 . ion))%%'' | + |