This is an old revision of the document!


Haskell: Structuri de date funcționale

  • Data publicării: 11.04.2023
  • Data ultimei modificări: 11.04.2023
  • Deadline hard: ziua laboratorului 10

Obiective

  • Aplicarea mecanismelor funcționale, de tipuri (inclusiv polimorfism) și de evaluare leneșă din limbajul Haskell.
  • Exploatarea evaluării leneșe pentru decuplarea conceptuală a prelucrărilor realizate.

Descriere generală și organizare

Tema urmărește familiarizarea cu specificul implementării structurilor de date în limbajele funcționale, problema eficienței fiind centrală. În limbajele imperative, eficiența este parțial alimentată de posibilitatea modificărilor distructive; de exemplu, actualizând în timp constant un element dintr-un vector. Prin contrast, în limbajele funcționale, modificările distructive sunt de obicei evitate, cu consecința persistenței structurilor de date. Cu alte cuvinte, dacă în abordarea imperativă dispunem de obicei doar de ultima variantă a unei structuri, care încorporează întregul istoric de modificări ale acesteia, în abordarea funcțională putem dispune simultan de toate versiunile intermediare ale acelei structuri. Ultima constrângere pare să impună costuri semnificative asupra implementării funcționale a structurilor de date, cu pierderi importante de eficiență. Vestea bună este că o reproiectare perspicace a acestor structuri poate recupera eficiența operațiilor; astfel, se combină complexitatatea comparabilă cu cea a structurilor imperative cu beneficiile purității funcționale.

Tema propune drept studiu de caz implementarea în Haskell a unei cozi de priorități, utilizând heap-uri binomiale. Implementarea imperativă standard a unui heap utilizează vectori și mizează pe accesul aleator în timp constant. După cum știm, listele înlănțuite din limbajele funcționale nu se pretează unei abordări fundamentate pe accesul aleator, care se realizează în timp liniar. Prin urmare, vom utiliza o reprezentare alternativă, în forma listelor de arbori binomiali, care oferă o complexitate logaritmică pentru toate operațiile, inclusiv pentru cea de combinare a două heap-uri, care în abordarea imperativă standard se realizează în timp liniar.

Tema este împărțită în 3 etape:

  • una pe care o veți rezolva după laboratorul 7, cu deadline în ziua laboratorului 8 (9 pentru seria CB)
  • una pe care o veți rezolva după laboratorul 8, cu deadline în ziua laboratorului 9 (10 pentru seria CB)
  • una pe care o veți rezolva după laboratorul 9, cu deadline în ziua laboratorului 10 (11 pentru seria CB).

Deadline-ul depinde de semigrupa în care sunteți repartizați. Restanțierii care refac tema și nu refac laboratorul beneficiază de ultimul deadline, și anume în zilele de 02.05, 09.05, respectiv 16.05.

Rezolvările tuturor etapelor pot fi trimise până în ziua laboratorului 10 (deadline hard pentru toate etapele). Orice exercițiu trimis după un deadline soft se punctează la jumătate. Cu alte cuvinte, nota finală pe etapă se calculează conform formulei: n = (n1 + n2) / 2 (n1 = nota obținută înainte de deadline; n2 = nota obținută după deadline). Când toate submisiile preced deadline-ul, nota pe ultima submisie constituie nota finală (întrucât n1 = n2).

În fiecare etapă, veți valorifica ce ați învățat în săptămâna anterioară și veți avea la dispoziție un schelet de cod, cu toate că rezolvarea se bazează în mare măsură pe etapele anterioare. Enunțul caută să ofere o imagine de ansamblu atât la nivel conceptual, cât și în privința aspectelor care se doresc implementate, în timp ce detaliile se găsesc direct în schelet.

Etapa 1

Operațiile pe heap-uri binomiale (cum este adăugarea unui nou element) sunt foarte similare conceptual celor pe numere binare (de exemplu, incrementare). Prin urmare, această etapă are un rol pregătitor, propunând o reprezentare a numerelor binare și definirea unor operații standard cu acestea. Heap-urile binomiale vor fi introduse propriu-zis în etapa 2.

Construcțiile și mecanismele de limbaj pe care le veți exploata în rezolvare sunt:

  • liste, pentru reprezentarea numerelor binare ca secvențe potențial infinite de biți
  • funcționale pe liste, ocazie cu care veți intra în contact atât cu cele standard, care se găsesc și în Racket, cât și cu altele specifice în Haskell
  • list comprehensions, pentru descrierea concisă a unor transformări
  • evaluare leneșă, implicită în Haskell, pentru decuplarea conceptuală a transformărilor din cadrul unei secvențe.

Modulul de interes din schelet este BinaryNumber, care conține reprezentarea numerelor binare și operațiile pe care trebuie să le implementați:

  • tipul BinaryNumber definește reprezentarea numerelor binare
  • funcția toDecimal convertește din reprezentarea binară în cea zecimală
  • funcția toBinary realizează conversia inversă
  • funcțiile inc și dec incrementează, respectiv decrementează cu 1 un număr binar, ținând cont bineînțeles de transport, respectiv împrumut
  • funcția add adună două numere binare
  • funcția stack pregătește terenul pentru înmulțirea a două numere binare, simulând maniera în care am dispune numerele pe hârtie, unul sub celălalt
  • funcția multiply realizează înmulțiri propriu-zise.

Găsiți detaliile despre funcționalitate și constrângeri de implementare, precum și exemple, direct în schelet. Aveți de completat definițiile care încep cu *** TODO ***.

Pentru rularea testelor, încărcați în interpretor modulul TestBinaryNumber și evaluați main.

Este suficient ca arhiva pentru vmchecker să conțină modulul BinaryNumber.

Precizări

  • Încercați să folosiți pe cât posibil funcții predefinite din modulul Data.List. Este foarte posibil ca o funcție de prelucrare de care aveți nevoie să fie deja definită aici.
  • Ca sugestie, exploatați cu încredere pattern matching, case și gărzi, în locul if-urilor imbricate.

Resurse

Changelog

pp/23/teme/haskell-structuri-functionale.1681232322.txt.gz · Last modified: 2023/04/11 19:58 by bot.pp
CC Attribution-Share Alike 3.0 Unported
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0