This shows you the differences between two versions of the page.
pp:21:laboratoare:racket:functionale [2021/03/15 16:16] bot.pp created |
pp:21:laboratoare:racket:functionale [2021/03/25 15:31] (current) bot.pp |
||
---|---|---|---|
Line 1: | Line 1: | ||
====== Racket: Funcții ca valori. Funcționale ====== | ====== Racket: Funcții ca valori. Funcționale ====== | ||
- | * Data publicării: 15.03.2020 | + | * Data publicării: 15.03.2021 |
* Data ultimei modificări: 15.03.2021 | * Data ultimei modificări: 15.03.2021 | ||
Line 18: | Line 18: | ||
* legate la un identificator: ''%%(define par? even?)%%'' | * legate la un identificator: ''%%(define par? even?)%%'' | ||
- | * stocate într-o structură de date: ''%%(list \< \> odd? even?)%%'' | + | * stocate într-o structură de date: ''%%(list < > odd? even?)%%'' |
* pasate ca argumente într-un apel de funcție: ''%%(list? even?)%%'' | * pasate ca argumente într-un apel de funcție: ''%%(list? even?)%%'' | ||
* returnate ca rezultat al unui apel de funcție: funcții curry din paragraful următor | * returnate ca rezultat al unui apel de funcție: funcții curry din paragraful următor | ||
Line 26: | Line 26: | ||
O funcție care își primește toți parametrii deodată se numește funcție **uncurry**. Până acum ați folosit doar funcții uncurry. | O funcție care își primește toți parametrii deodată se numește funcție **uncurry**. Până acum ați folosit doar funcții uncurry. | ||
- | <code> | + | <code lisp> |
(define add-uncurry | (define add-uncurry | ||
(lambda (x y) | (lambda (x y) | ||
Line 34: | Line 34: | ||
O funcție care returnează o nouă funcție atunci când este aplicată pe mai puține argumente decât îi sunt necesare se numește funcție **curry**. | O funcție care returnează o nouă funcție atunci când este aplicată pe mai puține argumente decât îi sunt necesare se numește funcție **curry**. | ||
- | <code> | + | <code lisp> |
(define add-curry | (define add-curry | ||
(lambda (x) | (lambda (x) | ||
Line 45: | Line 45: | ||
Funcțiile curry facilitează reutilizarea de cod, permițând obținerea unor funcții particulare din funcții mai generale: | Funcțiile curry facilitează reutilizarea de cod, permițând obținerea unor funcții particulare din funcții mai generale: | ||
- | <code> | + | <code lisp> |
(define inc-curry (add-curry 1)) | (define inc-curry (add-curry 1)) | ||
Line 53: | Line 53: | ||
În secvența de cod de mai jos sunt implementate două funcții. Prima funcție obține pătratele elementelor unei liste, iar a doua funcție obține cuburile elementelor listei. | În secvența de cod de mai jos sunt implementate două funcții. Prima funcție obține pătratele elementelor unei liste, iar a doua funcție obține cuburile elementelor listei. | ||
- | <code> | + | <code lisp> |
(define (sq x) (\* x x)) | (define (sq x) (\* x x)) | ||
(define (cub x) (\* x x x)) | (define (cub x) (\* x x x)) | ||
Line 73: | Line 73: | ||
După cum se poate observa, ambele funcții folosesc același pattern: | După cum se poate observa, ambele funcții folosesc același pattern: | ||
- | <code> | + | <code lisp> |
(define (?nume L) | (define (?nume L) | ||
(if (null? L) | (if (null? L) | ||
Line 84: | Line 84: | ||
Prin urmare, pentru a nu scrie de două ori același cod putem defini o altă funcție mai generală: | Prin urmare, pentru a nu scrie de două ori același cod putem defini o altă funcție mai generală: | ||
- | <code> | + | <code lisp> |
(define (general-func f L) | (define (general-func f L) | ||
(if (null? L) | (if (null? L) | ||
Line 93: | Line 93: | ||
Această funcție poate fi apoi folosită pentru a implementa sq-every și cub-every: | Această funcție poate fi apoi folosită pentru a implementa sq-every și cub-every: | ||
- | <code> | + | <code lisp> |
(define (sq-every L) (general-func sq L)) | (define (sq-every L) (general-func sq L)) | ||
(define (cub-every L) (general-func cub L)) | (define (cub-every L) (general-func cub L)) | ||
Line 102: | Line 102: | ||
Deoarece funcțiile sq si cub sunt folosite o singură dată, acestea pot fi scrise in-place ca funcții anonime: | Deoarece funcțiile sq si cub sunt folosite o singură dată, acestea pot fi scrise in-place ca funcții anonime: | ||
- | <code> | + | <code lisp> |
(define (sq-every-in-place L) (general-func (lambda (x) (\* x x)) L)) | (define (sq-every-in-place L) (general-func (lambda (x) (\* x x)) L)) | ||
(define (cub-every-in-place L) (general-func (lambda (x) (\* x x x)) L)) | (define (cub-every-in-place L) (general-func (lambda (x) (\* x x x)) L)) | ||
Line 109: | Line 109: | ||
Dacă dorim să scriem încă o funcție care să adune 2 la fiecare element al unei liste de numere, tot ce trebuie să facem este să folosim funcția general-func: | Dacă dorim să scriem încă o funcție care să adune 2 la fiecare element al unei liste de numere, tot ce trebuie să facem este să folosim funcția general-func: | ||
- | <code> | + | <code lisp> |
(define (+2-every L) (general-func (lambda (x) (+ 2 x)) L)) | (define (+2-every L) (general-func (lambda (x) (+ 2 x)) L)) | ||
Line 115: | Line 115: | ||
Însă codul de mai sus mai poate fi simplificat. Nu este nevoie să definim o nouă funcție pentru adunarea cu 2 a unui număr, ci ne putem folosi de funcția de adunare deja definită, pe care o aplicăm pe un singur parametru: | Însă codul de mai sus mai poate fi simplificat. Nu este nevoie să definim o nouă funcție pentru adunarea cu 2 a unui număr, ci ne putem folosi de funcția de adunare deja definită, pe care o aplicăm pe un singur parametru: | ||
- | <code> | + | <code lisp> |
(define (+2-every L) (general-func (add-curry 2) L)) | (define (+2-every L) (general-func (add-curry 2) L)) | ||
Line 129: | Line 129: | ||
* ''%%map%%'': returnează lista rezultatelor aplicării unei funcții f asupra fiecărui element dintr-o listă. [Obs: ''%%map%%'' poate primi n liste și atunci f are n parametrii, fiecare din câte o listă. Listele trebuie să aibă aceeași lungime] | * ''%%map%%'': returnează lista rezultatelor aplicării unei funcții f asupra fiecărui element dintr-o listă. [Obs: ''%%map%%'' poate primi n liste și atunci f are n parametrii, fiecare din câte o listă. Listele trebuie să aibă aceeași lungime] | ||
- | <code> | + | <code lisp> |
(map f L) | (map f L) | ||
Line 135: | Line 135: | ||
Mai jos se pot observa câteva exemple folosind map: | Mai jos se pot observa câteva exemple folosind map: | ||
- | <code> | + | <code lisp> |
(map add1 '(1 4 7 10)) ; întoarce '(2 5 8 11) | (map add1 '(1 4 7 10)) ; întoarce '(2 5 8 11) | ||
(map sqr '(1 2 3 4)) ; întoarce '(1 4 9 16) | (map sqr '(1 2 3 4)) ; întoarce '(1 4 9 16) | ||
Line 145: | Line 145: | ||
* ''%%filter%%'': returnează lista elementelor dintr-o listă care satisfac un predicat p. | * ''%%filter%%'': returnează lista elementelor dintr-o listă care satisfac un predicat p. | ||
- | <code> | + | <code lisp> |
(filter p L) | (filter p L) | ||
Line 151: | Line 151: | ||
Mai jos se pot observa câteva exemple folosind filter: | Mai jos se pot observa câteva exemple folosind filter: | ||
- | <code> | + | <code lisp> |
(filter even? '(1 3 4 7 8)) ; întoarce '(4 8) | (filter even? '(1 3 4 7 8)) ; întoarce '(4 8) | ||
(filter positive? '(1 -2 3 4 -5)) ; întoarce '(1 3 4) | (filter positive? '(1 -2 3 4 -5)) ; întoarce '(1 3 4) | ||
Line 159: | Line 159: | ||
* ''%%foldl%%'' (//fold left//): returnează rezultatul aplicării funcției f pe rând asupra unui element din listă și a unui acumulator. Ordinea folosirii elementelor din listă este de la stânga la dreapta. [Obs: ''%%foldl%%'' poate primi n liste și atunci f are (+ n 1) parametrii, dintre care ultimul este acumulatorul. Listele trebuie să aibă același număr de elemente] | * ''%%foldl%%'' (//fold left//): returnează rezultatul aplicării funcției f pe rând asupra unui element din listă și a unui acumulator. Ordinea folosirii elementelor din listă este de la stânga la dreapta. [Obs: ''%%foldl%%'' poate primi n liste și atunci f are (+ n 1) parametrii, dintre care ultimul este acumulatorul. Listele trebuie să aibă același număr de elemente] | ||
- | <code> | + | <code lisp> |
(foldl f init L) | (foldl f init L) | ||
Line 165: | Line 165: | ||
Mai jos se pot observa câteva exemple folosind foldl: | Mai jos se pot observa câteva exemple folosind foldl: | ||
- | <code> | + | <code lisp> |
(foldl cons null '(1 2 3 4)) ; întoarce '(4 3 2 1) | (foldl cons null '(1 2 3 4)) ; întoarce '(4 3 2 1) | ||
(foldl (lambda (x y result) (* result (+ x y))) 1 '(4 7 2) '(-6 3 -1)) ; întoarce -20 | (foldl (lambda (x y result) (* result (+ x y))) 1 '(4 7 2) '(-6 3 -1)) ; întoarce -20 | ||
Line 172: | Line 172: | ||
* ''%%foldr%%'' (//fold right//): singurele diferențe între foldl și foldr este că foldr ia elementele de la dreapta spre stânga și că are nevoie de un spațiu proporțional cu lungimea listei. | * ''%%foldr%%'' (//fold right//): singurele diferențe între foldl și foldr este că foldr ia elementele de la dreapta spre stânga și că are nevoie de un spațiu proporțional cu lungimea listei. | ||
- | <code> | + | <code lisp> |
(foldr f init L) | (foldr f init L) | ||
Line 178: | Line 178: | ||
Mai jos se pot observa câteva exemple folosind foldr: | Mai jos se pot observa câteva exemple folosind foldr: | ||
- | <code> | + | <code lisp> |
(foldr cons null '(1 2 3 4)) ; întoarce '(1 2 3 4) | (foldr cons null '(1 2 3 4)) ; întoarce '(1 2 3 4) | ||
(foldr (lambda (x acc) (cons (* x 2) acc)) null '(1 2 3 4)) ; întoarce '(2 4 6 8) | (foldr (lambda (x acc) (cons (* x 2) acc)) null '(1 2 3 4)) ; întoarce '(2 4 6 8) | ||
Line 185: | Line 185: | ||
* ''%%apply%%'': returnează rezultatul aplicării unei funcții f cu argumente elementele din lista L | * ''%%apply%%'': returnează rezultatul aplicării unei funcții f cu argumente elementele din lista L | ||
- | <code> | + | <code lisp> |
(apply f L) | (apply f L) | ||
Line 191: | Line 191: | ||
Mai jos se pot observa câteva exemple folosind apply: | Mai jos se pot observa câteva exemple folosind apply: | ||
- | <code> | + | <code lisp> |
(apply + '(1 2 3 4)) ; întoarce 10 | (apply + '(1 2 3 4)) ; întoarce 10 | ||
(apply * 1 2 '(3 4)) ; întoarce 24 | (apply * 1 2 '(3 4)) ; întoarce 24 | ||
Line 205: | Line 205: | ||
De multe ori, funcționalele ''%%map%%'' și ''%%apply%%'' sunt încurcate. Pentru a înțelege mai bine diferența dintre acestea, urmăriți rezultatele exemplelor de mai jos. | De multe ori, funcționalele ''%%map%%'' și ''%%apply%%'' sunt încurcate. Pentru a înțelege mai bine diferența dintre acestea, urmăriți rezultatele exemplelor de mai jos. | ||
- | <code> | + | <code lisp> |
(map list '(1 2 3)) ; întoarce'((1) (2) (3)) | (map list '(1 2 3)) ; întoarce'((1) (2) (3)) | ||
(apply list '(1 2 3)) ; întoarce '(1 2 3) | (apply list '(1 2 3)) ; întoarce '(1 2 3) | ||
Line 214: | Line 214: | ||
O altă greșeală întâlnită frecvent apare atunci când funcțiile primite ca argument de către funcționale sunt plasate între paranteze. | O altă greșeală întâlnită frecvent apare atunci când funcțiile primite ca argument de către funcționale sunt plasate între paranteze. | ||
- | <code> | + | <code lisp> |
(filter (odd?) '(1 2 3 4 5)) ; odd?: arity mismatch; (GREȘIT) | (filter (odd?) '(1 2 3 4 5)) ; odd?: arity mismatch; (GREȘIT) | ||
(filter odd? '(1 2 3 4 5)) ; întoarce '(1 3 5) (CORECT) | (filter odd? '(1 2 3 4 5)) ; întoarce '(1 3 5) (CORECT) |