Documente Academic
Documente Profesional
Documente Cultură
Primele 9 subiecte au ecare câte 10p. Cele 3 subpuncte ale problemei au ecare câte
10p. Punctajul NU se acord în absenta justic rii r spunsului! ,
1. Fie denitia si aplicatia functiei Racket de mai jos. Descrieti pas cu pas cum decurge
, , , , ,
1 (define (f x y)
2 (lambda (z)
3 (if (< x 10) (+ x y) z)))
4
Solut, ie. .
1 ((f (+ 0 1) (+ 2 3)) (+ 4 5))
2 → ((f 1 5) (+ 4 5))
3 → ((lambda (z) (if (< 1 10) (+ 1 5) z)) (+ 4 5))
4 → ((lambda (z) (if (< 1 10) (+ 1 5) z)) 9)
5 → (if (< 1 10) (+ 1 5) 9)
6 → (if true (+ 1 5) 9)
7 → (+ 1 5)
8 → 6
2. (V. sub. 1) Fie denitia si aplicatia functiei Haskell de mai jos. Descrieti pas cu pas
, , , , ,
3 > f (0 + 1) (2 + 3) (4 + 5)
Solut, ie. .
1 f (0 + 1) (2 + 3) (4 + 5)
2 → if (0 + 1) < 10 then (0 + 1) + (2 + 3) else (4 + 5)
3 → if 1 < 10 then 1 + (2 + 3) else (4 + 5)
4 → if True then 1 + (2 + 3) else (4 + 5)
5 → 1 + (2 + 3)
6 → 1 + 5
7 → 6
1 (define (f x)
2 (if (<= x 0) 0
3 (- (f (- x 1)) 1))) ; (f (- (f (- x 1)) 1))))
1
(b) Ce fel de recursivitate utilizeaz functia, dac înlocuim ultima linie cu expresia
,
comentat ?
Solut, ie. .
(a) Pe stiv , întrucât se mai realizeaz operatii dup evaluarea aplicatiei recursive.
, ,
1 (define (x x)
2 (let ([x x])
3 (x x)))
4
5 (x 0)
.
Solut, ie.
Eroare, deoarece aparitiile lui x din linia 3 se refer la parametrul functiei, 0, care nu
, ,
1 f u = map . u
Solut, ie. .
1 f :: d -> e
2 u :: d = a -> b
3 map :: (g -> h) -> [g] -> [h]
4 b = g -> h
5 c = [g] -> [h]
6 e = a -> c
7 f :: (a -> g -> h) -> a -> [g] -> [h]
6. Supraînc rcati în Haskell operatorul (<=) pe liste, astfel încât o list este mai mic sau
,
egal decât alta, dac acelasi lucru se poate arma si despre sumele elementelor lor.
, ,
Solut, ie. .
1 instance (Num a, Ord a) => Ord [a] where
2 xs <= ys = sum xs <= sum ys
α = p1 ∨ . . . ∨ p10
β = (p1 ∨ . . . ∨ p5 ) ∧ (p6 ∨ . . . ∨ p10 )
2
Solut, ie. .
Pentru n propozitii simple, exist 2n interpret ri distincte.
,
Toate interpret rile satisfac α, cu exceptia celei care asociaz Fals ec rei propozitii sim-
, ,
.
Solut, ie.
propozitii: ¬∀z.(P (z) ∨ Q(z)) ≡ ∃z.(¬P (z) ∧ ¬Q(z)). Astfel, în urma aplic rii procedurii
,
anticate existential z cu constanta cz , se obtin clauzele {P (x), Q(y)}, {¬P (cz )}, {¬Q(cz )}.
, ,
Unde ar trebui plasat operatorul cut, astfel încât scopul urm tor s e satisf cut?
1 ?- findall(_, c(X, Y), L), length(L, 4).
Solut, ie. .
1 c(X, Y) :- !, a(X), b(Y).
din liniile 5 si 6. ,
10. PROBLEMA. Puteti utiliza oricare dintre cele dou limbaje functionale studiate.
, ,
(a) Deniti reprezentarea unui arbore oarecare nevid, în care un nod poate avea oricâti
, ,
copii.
(b) Deniti o functie care calculeaz în ltimea arborelui. În ltimea unei frunze este 0.
, , , ,
(c) Deniti o functie care calculeaz num rul de frunze din arbore. Utilizati cel putin o
, , , ,
functional . ,
3
.
Solut, ie.
4
Preciz ri:
Primele 9 subiecte au ecare câte 10p. Cele 3 cerinte ale problemei au ecare câte 10p.
,
(a) (4p) Completati fraza: Pentru a evalua expresia utilizând modelul bazat pe substitutie
, ,
textual , trebuie înlocuite aparitiile (libere/legate?) _(1)_ ale variabilei _(2)_ din
,
(c) (3p) Ce pas lipseste pentru a obtine rezultatul corect? Scrieti rezultatul corect.
, , ,
Solut, ie. .
(c) Trebuie redenumit aparitia lui y din stânga lui E în z , obtinând λz.(y z), cu
, ,
Barem.
2p justicare
(c) 1p rezultatul corect
2p justicare
Solut, ie. .
1 (define (multicompose n f)
2 (let loop ([n n])
3 (if (zero? n)
4 (lambda (x) x)
5 (compose f (loop (- n 1))))))
Barem.
7p functionare corect
,
1
1p conditie caz de baz
,
3p named let
1p parametru
2p evitarea trimiterii lui f ca parametru la aplicatia recursiv
,
functii si o list de argumente, posibil de lungimi diferite, si aplic ecare functie pe ecare
, , , ,
Solut, ie. .
1 (define (cartesian-app fs xs)
2 (apply append
3 (map (lambda (f)
4 (map (lambda (x) (f x)) xs))
5 fs)))
Barem.
3p aplatizare list
1 (define s
2 (stream-cons 'x (stream-merge naturals s)))
.
Solut, ie.
0 1 2 3 ... (stream-merge)
s0 s1 s2 s3 ...
---------------------------
x | 0 s0 1 s1 2 s2 3 s3 ... =
s0 s1 s2 s3 s4 s5 s6 s7 ... =
x 0 x 1 0 2 x 3
2
Barem.
4p elementele (0,5p × 8)
1 f xs = head xs xs
Solut, ie. .
1 f :: a -> b
2 xs :: a
3 head :: [c] -> c
4 a = [c]
5 head xs :: c = d -> e
6 d = [c]
7 c = [c] -> e
Eroare de tip, întrucât s-ar obtine un tip innit, dac c s-ar lega la o expresie de tip care
,
îl contine strict.
,
Barem.
1p tip initial f si xs
, ,
1p tip head
1p unicare tip parametru formal/actual head (linia 4)
1p tip head xs
1p unicare tip parametru formal/actual head xs (linia 6)
2p unicare ciclic (linia 7)
3p conchidere eroare
6. Generalizati functionala filter din Haskell, având tipul (a -> Bool) -> [a] -> [a],
, ,
pentru a opera pe orice constructor de tip unar ce utilizeaz valori de tipul a, nu numai
pe constructorul list .
(a) (3p) Deniti clasa Filterable, parametrizat cum considerati de cuviint , în care
, , ,
(b) (2p) Instantiati Filterable, denit mai sus, cu constructorul list standard.
, ,
(c) (5p) Instantiati Filterable, denit mai sus, cu constructorul de tip Maybe,
, ,
denit prin
1 data Maybe a = Just a | Nothing
Solut, ie. .
3
1 class Filterable t where
2 filter’ :: (a -> Bool) -> t a -> t a
3
Barem.
(a) 1p antet
2p aplicare corect constructor de tip pe variabil de tip, t a
(b) 1p antet, instantiere cu [], nu cu [a]
,
1p denitie filter’,
1p caz Nothing
1p caz Just, conditie ,
Solut, ie. .
Se obtin clauzele {P (cy )} (2) si {¬Q(z)} (3), unde cy este constanta obtinut prin
, , ,
skolemizare.
4
(c) Aplicând rezolutia pe clauzele (1) si (2), cu legarea x ← cy , obtinem clauza {Q(cy )}
, , ,
(4). Aplicând din nou rezolutia pe clauzele (3) si (4), cu legarea z ← cy , obtinem
, , ,
clauza vid .
Barem.
1p scrierea clauzei
(b) 1p eliminarea implicatiei ,
1p scrierea clauzei
(c) 1p prima aplicare a rezolutiei ,
8. Deniti în Prolog predicatul group(+Xs, -Yss), care primeste o list de numere nenule
, ,
Xs, si leag lista de liste Yss, obtinute prin gruparea elementelor consecutive cu acelasi
, , ,
semn. De exemplu, interogarea group([1, 2, 3, -4, -5, 6], Yss) produce legarea
Yss = [[1, 2, 3], [-4, -5], [6]].
Solut, ie. .
1 group([], []).
2 % un singur element
3 group([X], [[X]]).
4 % cel putin 2 elemente, avand acelasi semn
5 group([X,Y|Zs], [[X|Rs]|Rss]) :- X*Y > 0, !, group([Y|Zs], [Rs|Rss]).
6 % cel putin 2 elemente, avand semn diferit
7 group([X,Y|T], [[X]|Rss]) :- group([Y|T], Rss).
Barem.
Prolog o interogare care determin lista tuturor listelor din Yss care contin cel putin , ,
dou dintre elementele lui Xs. De exemplu, dac Xs = [1, 2, 3] si Yss = [[1], [1, ,
2], [1, 3], [1, 3, 4], [1, 4, 5]], rezultatul este lista [[1, 2], [1, 3], [1,
3, 4]]. Atentie! NU folositi recursivitate explicit , ci metapredicate!
, ,
5
Solut, ie. .
1 findall(Ys,
2 (member(Ys, Yss),
3 findall(X,
4 (member(X, Xs), member(X, Ys)),
5 [_,_|_])),
6 Zss)
Barem.
2p parcurgere Yss
2p parcurgere Xs
2p vericare apartenent element din Xs la list individual din Yss
,
10. PROBLEMA. Se urm reste reprezentarea în Haskell a clauzelor din logica propozitional
, ,
date:
1 data Literal = Positive String
2 | Negative String
3 data Clause = Clause [Literal]
De exemplu, clauza {p, ¬q, r}, care corespunde disjunctiei p ∨ ¬q ∨ r, se poate reprezenta
,
pe clauza din exemplul de mai sus s se evalueze la sirul "p v ~q v r". Atentie!
, ,
(b) Deniti functia decompose, având tipul [a] -> [(a, [a])], care primeste o list
, , ,
-> Literal -> Bool, care veric dac doi literali sunt complementari (de exem-
plu, p si ¬p), scrieti functia resolve :: Clause -> Clause -> Maybe Clause,
, , ,
care rezolv dou clauze pe baza primei perechi de literali complementari, câte unul
din ecare clauz , dac aceasta exist . Hint : list comprehensions. Exemple:
resolve (Clause [Positive "p"]) (Clause [Negative "q"]) → Nothing
resolve (Clause [Positive "p"]) (Clause [Negative "p", Negative
"q"]) → Just (Clause [Negative "q"]).
Solut, ie. .
1 data Literal = Positive String | Negative String
2
6
4
Barem.
7
5p ad ugarea primului element al listei în fata celei de-a doua componente a
,
2p constructia rezolventului
,
1p caz Nothing
1p caz Just
8
Preciz ri:
Primele 9 subiecte au ecare câte 10p. Cele 3 cerinte ale problemei au ecare câte 10p.
,
1. Cu ce se pot înlocui punctele din expresia de mai jos, astfel încât aceasta s se evalueze
la z ?
(λx.(x y) . . .) → z
.
Solut, ie.
Barem.
3p forma nal
1 (define (f n x L)
2 (if (null? L)
3 L
4 (if (equal? (car L) x)
5 (if (= n 1)
6 (cdr L)
7 (cons (car L)
8 (f (sub1 n) x (cdr L))))
9 (cons (car L)
10 (f n x (cdr L))))))
(b) (5p) Rescrieti functia utilizând cel lalt tip de recursivitate si numiti-l.
, , , ,
Solut, ie. .
(a) Elimin a n-a aparitie a lui x din L. Utilizeaz recursivitate pe stiv .
,
1
Barem.
(a) 5p
3p functionalitate
,
2p tip recursivitate
(b) 5p
1p reverse acc
1p append (reverse acc) (cdr L)
1p prima aplicatie recursiv
,
1p tip recursivitate
3. Deniti în Racket functia mean, care calculeaz media elementelor unei liste, utilizând
, ,
Solut, ie. .
1 (define (mean L)
2 (let ([pair (foldl (lambda (x acc)
3 (cons (+ (car acc) x) (+ (cdr acc) 1)))
4 '(0 . 0)
5 L)])
6 (/ (car pair) (cdr pair))))
Barem.
2p functional corect,
1p caz de baz
3p cazul general
2p o singur trecere
2p evitare calcule duplicate
1 (define s
2 (stream-cons 1
3 (stream-cons 2
4 (stream-zip-with - s naturals))))
Solut, ie. .
Sc dem naturals din s, iar dac ad ug m 1 si 2 în fata rezultatului, obtinem s:
, , ,
s0 s1 s2 s3 s4 s5 ... (stream-zip-with -)
0 1 2 3 4 5 ...
-----------------------------------
1 2 | s0-0 s1-1 s2-2 s3-3 s4-4 s5-5 ... =
s0 s1 s2 s3 s4 s5 s6 s7 ... =
1 2 1 1 -1 -2 -5 -7
2
Barem.
4p elementele (0,5p × 8)
Solut, ie. .
1 map :: (a -> b) -> [a] -> [b] -- prima aparitie
2 map :: (c -> d) -> [c] -> [d] -- a doua aparitie
3 a -> b = (c -> d) -> [c] -> [d]
4 a = c -> d
5 b = [c] -> [d]
6 map map :: [c -> d] -> [[c] -> [d]]
Barem.
6. În Haskell, tipul operatorului de compunere este (.) :: (b -> c) -> (a -> b) ->
(a -> c). Ne propunem s generaliz m acest operator, astfel încât tipul rezultatului
întors s e împachetat într-un constructor de tip unar:
1 class Composable t where
2 compose :: (b -> t c)
3 -> (a -> t b)
4 -> (a -> t c)
(a) (2p) Dac dorim s instantiem clasa de mai sus cu constructorul de tip Maybe, care
,
Solut, ie. .
1 instance Composable Maybe where
2 -- (b -> Maybe c) -> (a -> Maybe b) -> (a -> Maybe c)
3 compose f g a = case g a of
4 Nothing -> Nothing
5 Just b -> f b
Barem.
(a) 2p
0,5p structura general a tipului
3
0,5p × 3 pt ecare tip intern de functie ,
(b) 8p
1p antet instant ,
1p parametri compose
1p aplicare (g a)
1p testare rezultat (g a)
2p caz Nothing
2p caz Just
7. Din punct de vedere logic, propozitia ∀x.(P (x) ∨ Q(x)) NU implic propozitia ∀y.P (y) ∨
, ,
∀z.Q(z) (gânditi-v la numere naturale, P ≡ par si Q ≡ impar , i.e. faptul c orice num r
, ,
natural e e par, e impar, nu implic faptul c e toate numerele sunt pare, e c toate
sunt impare). S presupunem c încerc m totusi s o demonstr m pe a doua din prima
,
de demonstrare?
.
Solut, ie.
Propozitia ∀x.(P (x) ∨ Q(x)) are forma clauzal {P (x), Q(x)} (1). Negând presupusa
,
concluzie, obtinem: ,
Se obtin clauzele {¬P (c)} (2) si {¬Q(d)} (3), unde c si d sunt constante obtinute prin
, , , ,
skolemizare. Rezolvând clauzele (1) si (2), cu legarea x ← c, obtinem clauza {Q(c)} (4).
, ,
Din p cate, nu putem rezolva mai departe clauzele (3) si (4), din cauz c nu putem ,
unica constantele c si d. ,
Barem.
1p clauza (1)
1p negarea concluziei
1p introducerea negatiei în paranteze ,
8. Se urm reste generarea în Prolog a combin rilor de K elemente dintr-o list de N ele-
,
mente, cu K ≤ N .
(a) (5p) Deniti predicatul extract(?Elem, +List, ?Rest), care leag parametrul
,
4
(b) (5p) Utilizând extract, deniti predicatul combs(+K, +List, ?Comb), care leag
,
Solut, ie. .
1 extract(X, [X|L], L).
2 extract(X, [_|T], R) :- extract(X, T, R).
3
4 combs(0, _, []) :- !.
5 combs(K, L, [X|C]) :- extract(X, L, M), K1 is K - 1, combs(K1, M, C).
Barem.
(a) 5p
2p cazul cu element pe prima pozitie în list
,
1p legare element
1p legare rest
3p cazul cu element în interiorul listei
1p aplicatie recursiv
,
1p legare element
1p legare rest
(b) 5p
0,5p cazul de baz
4p cazul general
1p aplicatie extract
,
1p calcul nou K
1p aplicatie recursiv
,
1p legare combinare
0,5p diferentiere corect între cazuri, e prin cut, e cu testare explicit a
,
9. Pornind de la o list de numere, Xs, si de la o list de liste de numere, Yss, scrieti în Prolog
, ,
o interogare care determin lista tuturor listelor din Yss care e au toate elementele în
Xs, e nu au niciun element în Xs. De exemplu, dac Xs = [1, 2, 3] si Yss = [[1, ,
4], [1, 3, 2], [4]], rezultatul este lista [[1, 3, 2], [4]]. Atentie! NU folositi
, ,
Solut, ie. .
1 findall( Ys,
2 ( member(Ys, Yss),
3 ( forall(member(Y, Ys), member(Y, Xs));
4 forall(member(Y, Ys), \+ member(Y, Xs))
5 )
6 ),
7 Zss
8 ).
5
Barem.
0p pt recursivitate explicit
10. PROBLEMA. Se urm reste reprezentarea în Haskell a unor propozitii (restrictionate)
, , ,
din logica cu predicate de ordinul I, utilizând urm toarele denitii de tipuri de date: ,
Astfel, un termen este o constant sau o variabil , iar o propozitie este un atom (aplicatia , ,
unui predicat pe niste termeni). De exemplu, utilizând notatia din Prolog, atomul p(X, c),
, ,
zenta prin Atom "p" [Var "X", Const "c"]. O substitutie este o multime de leg ri de , ,
zenta ca subst = [("X", Var "Y"), ("Y", Const "c")]. Pentru punctaj maxim,
toate functiile de mai jos trebuie implementate f r recursivitate explicit .
,
(a) Deniti functia lookup :: Substitution -> Term -> Term, care caut o vari-
, ,
abil într-o subtitutie si întoarce termenul aferent din pereche, dac ea este legat .
, ,
Pentru variabile nelegate sau pentru constante, functia întoarce termenul primit ca ,
Term -> [Term], care aplic la innit functia lookup pe rezultatul c ut rii ante- ,
rioare.
(b) Deniti functia lookupEnd :: Substitution -> Term -> Term, care întoarce
, ,
Sentence -> Bool, care veric dac doi atomi unic în baza substitutiei. Tre- ,
Exemple:
lookup subst (Var "X") → Var "Y"
lookup subst (Var "Z") → Var "Z"
lookup subst (Const "c") → Const "c"
take 4 $ lookupIterate subst (Var "X") → [Var "X", Var "Y", Const "c",
Const "c"]
lookupEnd subst (Var "X") → Const "c"
unifyTerms subst (Var "X") (Var "Y") → True
6
unifyTerms subst (Var "X") (Const "c") → True
unifyTerms subst (Var "X") (Const "d") → False
unifyTerms subst (Const "c") (Const "d") → False
unifySentences subst (Atom "p" [Var "X", Const "c"]) (Atom "p" [Var
"Y", Var "X"]) → True
unifySentences subst (Atom "p" [Var "X", Const "c"]) (Atom "u" [Var
"Y", Var "X"]) → False
unifySentences subst (Atom "p" [Var "X", Const "c"]) (Atom "p" [Var
"Y", Const "d"]) → False
Solut, ie. .
1 data Term
2 = Const String
3 | Var String
4 deriving (Eq, Show)
5
11 subst :: Substitution
12 subst = [("X", Var "Y"), ("Y", Const "c")]
13
7
Barem.
(a) 8p lookup
3p absenta recusivit tii explicite
, ,
1p parcurgere substitutie,
8
Examen PP varianta A — NOT EXAM MODE
31.05.2019
atent, ie: Avet, i 2 ore · 1-9: 10p; 10: 30p · 100p pentru nota maximă · Justificat, i răspunsurile!
3. Date fiind două liste de numere L1 s, i L2, scriet, i ı̂n Racket codul care produce o listă de perechi (x .
n), unde x este un element din L1, iar n este numărul de aparit, ii ale lui x ı̂n L2. E.g. pentru L1 =
(1 4 5 3) s, i L2 = (1 3 2 4 1 5 3 9) rezultatul este ((1 . 2) (4 . 1) (5 . 1) (3 . 2)). Nu
folosit, i recursivitate explicită.
Solut, ie:
(map (lambda (x) (cons x (length (filter ((curry equal?) x) L)))) ’(1 4 5 3))
sau
(map (lambda (x) (cons x (length (filter (lambda (y) (equal? x y)) L)))) ’(1 4 5 3))
5. (a) Cât, i pas, i de concatenare sunt realizat, i pentru evaluarea expresiei Racket
(car (append ’(1 2) ’(3 4))) ?
(b) Dar pentru expresia Haskell head $ [1, 2] ++ [3, 4] ?
Solut, ie:
(a) Se concatenează ı̂ntregime listele, deci doi pas, i.
(b) Este suficient un singur pas pentru ca head să ı̂ntoarcă primul element.
7. Transformat, i propozit, ia ,,Nu tot ce zboară se mănâncă.” ı̂n logică cu predicate de ordinul ı̂ntâi.
Solut, ie:
∃x.zboara(x) ∧ ¬se mananca(x) – există s, i lucruri care zboară s, i nu se mănâncă
sau
¬(∀x.zboara(x) ⇒ se mananca(x)) – nu este adevărat că orice care zboară automat se s, i mănâncă
8. Se dă programul Prolog:
p(R, S) :- member(X, R),
findall(Y, (member(Y, R), Y \= X), T), !, q(X, T, S).
q(X, A, [X|A]). q(X, [A|B], [A|C]) :- q(X, B, C).
Dacă predicatul p primes, te ı̂n primul argument o listă, la ce valori leagă al doilea argument? Câte
solut, ii are interogarea p([1, 2, 3, 4], S) ?
Solut, ie:
Ia primul element (s, i elimină duplicatele lui) s, i ı̂l pune pe diverse pozit, ii ale listei, inclusiv pe prima.
Patru solut, ii: [1, 2, 3, 4], [2, 1, 3, 4], [2, 3, 1, 4], [2, 3, 4, 1]
9. Se dau următoarele relat, ii genealogice prin predicatul c(Parinte, Copil). Implementat, i predicatul
frati(X, F), care leagă F la lista de frat, i ai lui X (dacă există). De exemplu, pentru definit, iile de
mai jos, interogarea frati(herodot, F) leagă F la [faramir, george].
c(alex, celia). c(alex, delia). c(alex, marcel).
c(barbra, celia). c(barbra, delia). c(barbra, marcel).
c(delia, faramir). c(delia, george). c(delia, herodot).
c(erus, faramir). c(erus, george). c(erus, herodot).
Solut, ie:
frati(X, F) :- c(P, X), !, findall(Y, (c(P, Y), Y \= X), F). sau
frati(X, F) :- findall(Y, (c(P, X), c(P, Y), Y \= X), F1), sort(F1, F).
10. PROBLEMA (Poate fi implementată ı̂n orice limbaj studiat la PP.) Se urmăres, te implementarea
unui multi-map, care este un tabel asociativ ı̂n care unei chei i se pot asocia oricâte valori.
(a) Descriet, i reprezentarea multi-map-ului. Pentru Haskell, dat, i definit, ia tipului de date polimorfic.
Definit, i funct, ia/predicatul lookup’, care extrage lista tuturor valorilor asociate cu o cheie.
(b) Definit, i funct, ia/predicatul insert’, pentru adăugarea unei noi asocieri ı̂ntre o cheie s, i o valoare.
(c) Definit, i funct, ia/predicatul map’, care aplică o funct, ie/predicat pe fiecare valoare din multi-map.
Notă: ı̂n Prolog, map’ va aplica ı̂ntotdeauna un acelas, i predicat p(+VIn, -VOut).
Solut, ie:
Racket:
(define multimapExample ’((a 1 2 3) (b 5 6 7) (c 7 8)))
(define (insert k v m)
(let-values (((bef aft) (splitf-at m (λ(kv) (not (equal? (car kv) k))))))
(if (null? aft)
(cons (list k v) m)
(append bef (list (cons k (cons v (cdar aft)))) (cdr aft))
)))
(insert ’d 5 multimapExample)
(insert ’b 9 multimapExample)
(define (mmap f m)
(map
(lambda (kv) (cons (car kv) (map f (cdr kv))))
m))
(mmap add1 multimapExample)
Haskell:
data MultiMap k a = MM [(k, [a])] deriving (Eq, Show)
f(V, V1) :- V1 is V + 1.
map(MM, Out) :-
findall((K, L1),
( member((K, L), MM),
findall(E1, (member(E, L), f(E, E1)), L1)),
Out).
Examen PP varianta B — NOT EXAM MODE
31.05.2019
atent, ie: Avet, i 2 ore · 1-9: 10p; 10: 30p · 100p pentru nota maximă · Justificat, i răspunsurile!
3. Dată fiind o listă de liste de numere LL, scriet, i ı̂n Racket codul care produce sublista lui LL ı̂n care
pentru toate elementele L suma elementelor este cel put, in egală cu produsul lor. E.g. pentru L = ((1
2 3) (1 2) (4 5) (.5 .5)) rezultatul este ((1 2 3) (1 2) (0.5 0.5)). Nu folosit, i recursivitate
explicită.
Solut, ie:
(filter (lambda (L) (>= (apply + L) (apply * L))) ’((1 2 3) (1 2) (4 5) (.5 .5)))
5. (a) Câte aplicat, ii ale funct, iei de incrementare sunt calculate pentru evaluarea expresiei Racket
(length (map add1 ’(1 2 3 4 5 6 7 8 9 10))) ?
(b) Dar pentru expresia Haskell length $ map (+ 1) [1 .. 10] ?
Solut, ie:
(a) Toate elementele listei sunt evaluate, deci 10.
(b) Elementele listei nu sunt evaluate, deci 0.
6. Supraı̂ncărcat, i ı̂n Haskell operatorii (+) s, i (*) pentru valori booleene, pentru a surprinde operat, iile
de sau, respectiv s, i logic.
Solut, ie:
instance Num Bool where
(+) = (||)
(*) = (&&)
7. Transformat, i propozit, ia ,,Nu mor caii când vor câinii.” ı̂n logică cu predicate de ordinul ı̂ntâi, folosind
predicatele caii mor(c^and) s, i c^ainii vor(c^and).
Solut, ie:
∃t.cainii vor(t) ∧ ¬caii mor(t) – există s, i momente când câinii vor dar caii nu mor
sau
¬(∀t.cainii vor(t) ⇒ caii mor(t)) – nu este adevărat că oricând câinii vor automat caii mor
8. Se dă programul Prolog:
p( , [], []).
p(A, [A|B], B) :- !.
p(A, [B|C], [B|D]) :- p(A, C, D). Ce relat, ie există ı̂ntre cele 3 valori X, Y, Z, dacă p(X, Y, Z)
este adevărat?
Solut, ie:
Este predicatul select, iar dacă primul argument este nelegat face select la primul element. Pre-
dicatul select(X, Y, Z) este adevărat dacă X este un element din lista Y, iar Z este exact lista Y, ı̂n
afară de elementul X.
9. Se dau următoarele relat, ii genealogice prin predicatul c(Parinte, Copil). Implementat, i predicatul
veri(X, V), care leagă V la lista de veri ai lui X (dacă există). De exemplu, pentru definit, iile de mai
jos, interogarea veri(faramir, V) leagă V la [jenny, karl, ninel, octav].
c(alex, celia). c(alex, delia). c(alex, marcel).
c(barbra, celia). c(barbra, delia). c(barbra, marcel).
c(delia, faramir).
c(ion, jenny). c(ion, karl). c(celia, jenny). c(celia, karl).
c(marcel, ninel). c(marcel, octav).
Solut, ie:
veri(X, L) :- setof(V, P∧ B∧ U∧ (c(P, X), c(B, P), c(B, U), U\=P, c(U, V)), L). sau
veri(X, L) :- findall(V, (c(P, X), c(B, P), c(B, U), U\=P, c(U, V)), L1), sort(L1, L).
10. PROBLEMA (Poate fi implementată ı̂n orice limbaj studiat la PP.) Se urmăres, te implementarea
unui hash set, care reprezintă o mult, ime grupând valorile ı̂n bucket-uri, fiecare bucket fiind unic
determinat de hash-ul valorilor din bucket (toate valorile din bucket au acelas, i hash). Hashul unei
valori va fi dat de funct, ia hash, respectiv predicatul hash(+V, -Hash).
(a) Descriet, i reprezentarea hash set-ului. Pentru Haskell, dat, i definit, ia tipului de date polimorfic.
Definit, i funct, ia/predicatul values’, care extrage lista tuturor valorilor asociate cu un hash.
(b) Definit, i funct, ia/predicatul insert’, pentru adăugarea unei valori.
(c) Definit, i funct, ia/predicatul map’, care aplică o funct, ie/predicat pe fiecare valoare din hash-set.
Notă: ı̂n Prolog, map’ va aplica ı̂ntotdeauna un acelas, i predicat p(+VIn, -VOut).
Solut, ie:
Racket:
(define (hash int) (remainder int 2))
(define hashExample ’((1 3 5 7) (0 0 2 8)))
(define (insert v m)
(let ((k (hash v)))
(let-values (((bef aft) (splitf-at m (λ(kv) (not (equal? (car kv) k))))))
(if (null? aft)
(cons (list k v) m)
(append bef (list (cons k (cons v (cdar aft)))) (cdr aft))
))))
(insert 9 hashExample)
(insert 9 (cdr hashExample))
(define (mmap f m)
(map
(λ(kv) (cons (car kv) (map f (cdr kv))))
m))
(mmap add1 hashExample)
Haskell:
class Hashable a where hash :: a -> Int -- nu a fost cerut ^ın rezolvare
instance Hashable Int where hash x = mod x 2 -- nu a fost cerut ^
ın rezolvare
f(V, V1) :- V1 is V + 1.
map(HS, Out) :-
findall((K, L1),
( member((K, L), HS),
findall(E1, (member(E, L), f(E, E1)), L1)),
Out).
Varianta A – Examen PP (2020)
(define (z x y)
(if (or (null? x) (null? y))
'()
(cons (car x) (cons (car y) (z (cdr y) (cdr x))))))
Definit, i (tot ı̂n Racket) cât mai eficient funct, ia zz care are acelas, i efect cu z, dar foloses, te un
alt tip de recursivitate.
Justificat, i pe scurt eficient, a solut, iei voastre.
Solut, ie:
Recursivitate pe stivă – o vom transforma ı̂n recursivitate pe coadă.
(define (zz x y)
(let z ((x x) (y y) (r '()))
(if (or (null? x) (null? y))
(reverse r)
(z (cdr y) (cdr x) (cons (car y) (cons (car x) r))))))
Eficient, ă:
3. Atent, ie: Acest exercit, iu nu se punctează decât dacă este rezolvat fără a folosi recursivitate
explicită (deci nici letrec sau named let). Solut, iile explicit recursive se punctează cu 0.
Se dă o listă L care cont, ine numere s, i/sau liste de numere (maxim un nivel de imbricare).
Să se definească, ı̂n Racket, funct, ia two-sums care ı̂ntoarce o pereche de valori, reprezentând
suma numerelor la ”adâncime 0” din L, respectiv suma numerelor la ”adâncime 1” din L.
ex: (two-sums ’(1 2 (3 4) 5 (6) 7)) va ı̂ntoarce ’(15 . 13), pentru că 1 + 2 + 5 + 7 =
15, iar 3 + 4 + 6 = 13
Solut, ie:
(define (two-sums L)
(let ((outside (filter (compose not list?) L))
(inside (apply append (filter list? L))))
(cons (apply + outside) (apply + inside))))
[] ++ ys = ys
(x : xs) ++ ys = x : (xs ++ ys)
Solut, ie:
Solut, ie:
f :: a = d -> e
x :: b = d
c = e
fs :: [a] = [d -> e]
xs :: [b] = [d]
g :: [d -> e] -> [d] -> [e]
6. Supraı̂ncărcat, i ı̂n Haskell operatorul de egalitate pentru funct, ii unare cu parametru numeric,
astfel ı̂ncât două funct, ii să fie considerate egale dacă valorile lor coincid ı̂n cel put, in 10 puncte
din intervalul 1, . . . , 100.
Solut, ie:
7. Folosit, i pentru scriere NOT(), AND s, i OR ca operatori logici s, i ORICARE s, i EXISTĂ drept cuantifi-
catori. Scriet, i cu caps ca să nu existe confuzii cu limbajul obis, nuit. Putet, i prescurta numele
predicatelor.
S, tiind că ”Cine ı̂mparte (din ceva), parte ı̂s, i face (din acel ceva).”, s, i că
ıs, i face parte din(marcel, tort)), dorim să demonstrăm că NOT(^
NOT(^ ımparte(marcel,
tort)).
a) Traducet, i proverbul ı̂n LPOI (FOL) utilizând numai predicatele ment, ionate ı̂n problemă.
b) Demonstrat, i prin metoda rezolut, iei concluzia cerută.
a) ∀X.∀Y.^
ımparte(X, Y) ⇒ ı
^s, i face parte(X, Y)
b) Clauzele:
(1) ¬^ımparte(X, Y) ∨ ı ^s, i face parte din(X, Y)
(2) ı
^mparte(marcel, tort)
(3) ¬^ıs, i face parte din(marcel, tort)
(1) + (2) {X ← marcel} → ı ^s, i face parte din(marcel, tort) (4)
(3) + (4) → (clauza vidă)
8. Implementat, i predicatul filtersorted(+LLIn, -LLOut), care primes, te ı̂n LLIn o listă de
liste de numere s, i pune ı̂n LLOut doar acele liste de numere care sunt sortate crescător.
De exemplu, filtersorted([[2, 1], [1, 3], [1, 2, 3, 4], [1, 2, 4, 2]], X) leagă
X la [[1, 3], [1, 2, 3, 4]]. Explicat, i cum funct, ionează implementarea.
Solut, ie:
filtersorted([], []).
filtersorted([E|LLIn], [E|LLOut]) :- sort(E, E), !, filtersorted(LLIn, LLOut).
filtersorted([_|LLIn], LLOut) :- filtersorted(LLIn, LLOut).
9. Folosit, i unul sau mai multe dintre predicatele findall, forall, bagof, setof pentru a im-
plementa predicatul med(+L, -Med), care găses, te elementul median al listei, cu proprietatea
că numărul de elemente mai mari decât Med este diferit cu cel mult 1 de numărul de elemente
mai mici decât Med). Nu utilizat, i recursivitate explicită. Explicat, i cum funct, ionează solut, ia.
Solut, ie:
med(L, Med) :- member(Med, L), findall(X, (member(X, L), X < Med), L1),
findall(X, (member(X, L), X > Med), L2), length(L1, LL1),
length(L2, LL2), abs(LL1-LL2) =< 1.
10. În acest exercit, iu urmărim crearea unui index de cuvinte dintr-un text: pentru fiecare cuvânt,
vom avea o listă cu liniile din text pe care acest apare. În acest scop definim următoarele
alias-uri de tip.
Utilizat, i următorul schelet:
import Data.List
import Data.Char
import Data.Maybe
• (10p) Un text constă ı̂ntr-un string de cuvinte care pot fi separate prin spat, ii sau enter
(caracterul \n). De asemenea, ı̂n text pot apărea semne de punctuat, ie precum virgulă,
punct, semnul ı̂ntrebării sau semnul exclamării (după care apare minim un spat, iu sau
enter).
Să se implementeze funct, ia textToLines care primes, te un text s, i ı̂ntoarce o listă de
perechi de forma: (linie, text aflat pe acea linie procesat).
Un text procesat reprezintă textul din care s-au eliminat semnele de punctuat, ie iar
literele mari au fost transformate ı̂n litere mici.
{-
Utile:
-- ^
ımparte un text ^ın linii, pars^and după '\n'
lines :: String -> [String]
-- transformă o literă mare ^
ın literă mică
toLower :: Char -> Char
ex:
*Main> textToLines "A venit,\na venit\ntoamna!"
[(1,"a venit"),(2,"a venit"),(3,"toamna")]
-}
ex:
*Main> allPairs "A venit,\na venit\ntoamna!"
[("a",1),("venit",1),("a",2),("venit",2),("toamna",3)]
*Main> textToIndex "A venit,\na venit\ntoamna!"
[("a",[1,2]),("toamna",[3]),("venit",[1,2])]
-}
allPairs :: Text -> [Pair]
allPairs = undefined
Solut, ie:
-1.
textToLines :: Text -> [(Int, Text)]
textToLines = zip [1 ..] . lines . map toLower . filter (`notElem` ",.?!")
--2.
insPair :: Pair -> Index -> Index
insPair (word, line) index = case lookup word index of
Nothing -> (word, [line]) : index
Just lines -> if elem line lines then index
else (word, line : lines) : filter ((/=
,→ word) . fst) index
--3.
allPairs :: Text -> [Pair]
allPairs txt = [ (word, line) | (line, text) <- textToLines txt, word <-
,→ words text ]
Solut, ie:
(define my-stream
(stream-cons '(1)
(stream-map (lambda (L) (let ([new (list (add1 (car L)))])
(append new L new)))
my-stream)))
g f (x, y) = x ++ map f y
Solut, ie:
g :: a -> b -> c
f :: a = d -> e
(x, y) :: b = (i, j)
(++) :: [k] -> [k] -> [k]
map :: (m -> n) -> [m] -> [n]
i = [k]
d -> e = m -> n
d = m
e = n
j = [m]
[n] = [k]
n = k
c = [k]
g :: (m -> k) -> ([k], [m]) -> [k]
6. Scriet, i o instant, ă posibilă a clasei de mai jos, cont, inând o implementare neconstantă a
funct, iei f.
Solut, ie:
7. Folosit, i pentru scriere NOT(), AND s, i OR ca operatori logici s, i ORICARE s, i EXISTĂ drept cuantifi-
catori. Scriet, i cu caps ca să nu existe confuzii cu limbajul obis, nuit. Putet, i prescurta numele
predicatelor.
S, tiind că ”Capul plecat, sabia nu ı̂l taie”, s, i că i se taie capul lui(marcel), dorim să
demonstrăm că NOT(are capul plecat(marcel)).
a) Traducet, i proverbul ı̂n LPOI (FOL) utilizând numai predicatele ment, ionate ı̂n problemă.
b) Demonstrat, i prin metoda rezolut, iei concluzia cerută.
g(_, 0, []).
g([E|T], Len, [E|R]) :- Len > 0, Len1 is Len - 1, append(T, [E], T1), g(T1, Len1, R).
9. Folosit, i o singură dată unul dintre predicatele findall, forall, bagof, setof pentru a
implementa predicatul minmax(+L, -Min, -Max) care leagă Min, respectiv Max, la elemen-
tul minim, respectiv maxim, al listei. Nu utilizat, i recursivitate explicită. Explicat, i cum
funct, ionează solut, ia.
Solut, ie:
10. În acest exercit, iu urmărim crearea s, i exploatarea unei tabele de frecvent, ă pentru caracterele
care apar ı̂n cuvinte diferite dintr-un text. O tabelă de frecvent, ă este o colect, ie de asocieri
ı̂ntre un caracter s, i frecvent, a sa de aparit, ie.
Utilizat, i următorul schelet:
import Data.List
import Data.Char
import Data.Maybe
• (10p) Să se creeze aliasul de tip FreqTable, pentru tabele de frecvent, ă.
Să se implementeze funct, ia rareChars, care primes, te o tabelă de frecvent, ă s, i un număr
n s, i ı̂ntoarce lista caracterelor din tabelă care au frecvent, a mai mică decât n.
Exemplu:
*Main> rareChars [('a',3), ('b',1), ('c',2), ('d',1)] 2
"bd"
type FreqTable = Int -- aici trebuie modificat ^
ın altceva dec^
at Int
Solut, ie:
--1.
type FreqTable = [(Char, Int)]
--2.
insChar :: Char -> FreqTable -> FreqTable
insChar c table = case lookup c table of -- nu e nevoie de lookup, merge s, i
,→ filter simplu sau recursivitate
Nothing -> (c, 1) : table
Just f -> (c, f+1) : filter ((/= c) . fst) table
--3.
textToStr :: String -> String
textToStr = concat . nub . words -- duplicatele se pot elimina s, i cu un fold
,→ simplu (ca la lab3)
(define (t x)
(cond ((or (< x 0) (even? x)) 0)
((< x 5) (quotient x 2))
(else (+ (t (- x 2)) (t (- x 4))))))
Definit, i (tot ı̂n Racket) cât mai eficient funct, ia tt care are acelas, i efect cu t, dar foloses, te un
alt tip de recursivitate.
Care este noul tip de recursivitate?
Solut, ie:
Recursivitate arborescentă – o vom transforma ı̂n recursivitate pe coadă.
3. Atent, ie: Acest exercit, iu nu se punctează decât dacă este rezolvat fără a folosi recursivitate
explicită (deci nici letrec sau named let). Solut, iile explicit recursive se punctează cu 0.
Se dă o listă L care cont, ine numere s, i/sau liste de numere (maxim un nivel de imbricare).
Să se definească, ı̂n Racket, funct, ia longest-list care ı̂ntoarce lista de lungime maximă din
input - fie ı̂ntreg L, fie una din listele interioare lui L.
ex: (longest-list ’(0 1 2 (3 4 3 4 3 4 3 4 3 4) 5 (6) 7)) va ı̂ntoarce ’(3 4 3 4
3 4 3 4 3 4) - pt ca are lungimea 10
(longest-list ’(0 1 2 (3 4 3 4 3 4) 5 (6) 7)) va ı̂ntoarce ’(0 1 2 (3 4 3 4 3 4)
5 (6) 7)) - pt ca are lungimea 7
Solut, ie:
(define (longest-list L)
(let ((inner-lists (filter list? L)))
(foldr (lambda (L acc) (if (> (length L) (length acc)) L acc))
L
inner-lists)))
4. Definit, i ı̂n Racket fluxul coeficient, ilor binomiali:
'((1) (1 1) (1 2 1) (1 3 3 1) (1 4 6 4 1) (1 5 10 10 5 1) ...)
Solut, ie:
(define binomial-stream
(stream-cons '(1)
(stream-map (lambda (L) (let ([M (cons 0 L)]) (map + M (reverse M))))
binomial-stream)))
f x y = f (f x y) (f y x)
Solut, ie:
f :: a -> b -> c
x :: a
y :: b
a = b
c = a = b
f :: a -> a -> a
6. Scriet, i o instant, ă posibilă a clasei de mai jos, cont, inând o implementare neconstantă a
funct, iei f.
Solut, ie:
7. Folosit, i pentru scriere NOT(), AND s, i OR ca operatori logici s, i ORICARE s, i EXISTĂ drept cuantifi-
catori. Scriet, i cu caps ca să nu existe confuzii cu limbajul obis, nuit. Putet, i prescurta numele
predicatelor.
S, tiind că ”Unde intră soarele pe fereastră, nu intră doctorul pe us, ă.”, că doctor(hipocrate),
că locuint, ă(apartamentul 2), s, i că intră pe us, ă(hipocrate, apartamentul 2), dorim
să demonstrăm că NOT(intră soarele pe vreo fereastră din(apartamentul 2)).
a) Traducet, i proverbul ı̂n LPOI (FOL) utilizând numai predicatele ment, ionate ı̂n problemă.
b) Enumerat, i toate clauzele necesare demonstrat, iei (inclusiv negarea concluziei), ilustrând
pe scurt cum at, i ajuns la ele.
a([], _, _, []).
a(_, [], _, []).
a(_, _, [], []).
a([H1|L1], [H2|L2], [H3|L3], [(H1, H2, H3) | L123]) :- a(L1, L2, L3, L123).
9. Folosit, i unul sau mai multe dintre predicatele findall, forall, bagof, setof pentru a im-
plementa predicatul secondMin(+L, -X) care găses, te al doilea cel mai mic element din lista L
(care cont, ine cel put, in 2 elemente s, i nu cont, ine duplicate). Nu utilizat, i recursivitate explicită.
Explicat, i cum funct, ionează solut, ia.
Solut, ie:
10. Problema urmăres, te reprezentarea unor propozit, ii din logica propozit, ională s, i implementarea
unei transformări asupra acestora.
Utilizat, i următorul schelet:
• (8p) Elaborat, i reprezentarea propozit, iilor logice ı̂n forma unui tip de date Haskell.
Propozit, iile vor putea consta ı̂n:
– propozit, ii simple (exemplu: p, q, r etc.)
– negat, ii (exemplu: ¬p)
– conjunct, ii (exemplu: p ∧ q)
– disjunct, ii (exemplu: p ∨ q).
data Prop
= Undefined
• (2p) Pornind de la reprezentarea de mai sus, traducet, i propozit, ia ¬(p ∧ (¬q ∨ r)).
prop :: Prop
prop = undefined
• (10p) Instant, iat, i clasa Show cu tipul Prop. Reprezentarea sub formă de s, ir a propozit, iei
prop ar trebui să fie cea din cerint, a de mai sus.
instance Show Prop where
show = undefined
• (10p) Implementat, i funct, ia processNeg, care urmăres, te introducerea negat, iilor ı̂n paran-
teze. De exemplu:
show (processNeg prop) va furniza (¬p ∨ (q ∧ ¬r))
processNeg :: Prop -> Prop
processNeg = undefined
Solut, ie:
-- 1.1
data Prop
= Simple Char
| Neg Prop
| And Prop Prop
| Or Prop Prop
-- 1.2
prop :: Prop
prop = Neg $ Simple 'p' `And` (Neg (Simple 'q') `Or` Simple 'r')
-- 2
instance Show Prop where
show (Simple c) = [c]
show (Neg p) = "~" ++ show p
show (And p1 p2) = "(" ++ show p1 ++ " ^ " ++ show p2 ++ ")"
show (Or p1 p2) = "(" ++ show p1 ++ " v " ++ show p2 ++ ")"
-- 3
processNeg :: Prop -> Prop
processNeg p@(Simple _) = p
processNeg (Neg p) = case p of
Simple _ -> Neg p
Neg p' -> processNeg p'
And p1 p2 -> processNeg $ Or (Neg p1) (Neg p2)
Or p1 p2 -> processNeg $ And (Neg p1) (Neg p2)
processNeg (And p1 p2) = And (processNeg p1) (processNeg p2)
processNeg (Or p1 p2) = Or (processNeg p1) (processNeg p2)
Varianta D – Examen PP (2020)
(define (w x)
(let h ((x x) (r 0))
(if (null? x)
(* 2 r)
(add1 (h (cdr x) (if (even? (car x)) r (add1 r)))))))
Definit, i (tot ı̂n Racket) cât mai eficient funct, ia ww care are acelas, i efect cu w, dar foloses, te un
alt tip de recursivitate.
Precizat, i pe scurt care modificare din cod a dus la modificarea tipului de recursivitate.
Solut, ie:
Recursivitate pe stivă – o vom transforma ı̂n recursivitate pe coadă.
(define (ww x)
(let h ((x x) (r 0))
(if (null? x)
r
(h (cdr x) (if (even? (car x)) (add1 r) (+ r 3)))))) ;; ^ınainte
,→ aveam add1 pe apelul recursiv (stivă), acum apelul recursiv
,→ este la coadă, toate adunările se fac asupra acumulatorului r
3. Atent, ie: Acest exercit, iu nu se punctează decât dacă este rezolvat fără a folosi recursivitate
explicită (deci nici letrec sau named let). Solut, iile explicit recursive se punctează cu 0.
Se dă o listă L de numere. Să se definească, ı̂n Racket, funct, ia count-smaller care ı̂ntoarce o
listă de perechi de forma (număr n din L . c^ ate valori din L sunt mai mici ca n). Atent, ie,
fiecare număr din L trebuie să apară o singură dată ı̂n partea din stânga a perechilor!
ex: (count-smaller ’(1 2 3 2 4 3 1 2)) va ı̂ntoarce ’((4 . 7) (3 . 5) (2 . 2)
(1 . 0)) - sau aceleas, i 4 perechi ı̂n orice altă ordine (ordinea NU contează), pentru că ı̂n
L sunt 7 numere mai mici ca 4, 5 mai mici ca 3, 2 mai mici ca 2, s, i niciunul mai mic ca 1.
Solut, ie:
(define (count-smaller L)
(let ((no-dups (foldl (lambda (n acc) (if (member n acc) acc (cons n
,→ acc))) '() L)))
(map (lambda(n) (cons n (length (filter (lambda (x) (< x n)) L))))
,→ no-dups)))
4. Se dau ı̂n Racket două fluxuri de liste, s1 s, i s2. Definit, i fluxul ale căror elemente se obt, in
prin intersectarea listelor de pe aceeas, i pozit, ie din s1 s, i s2.
Exemplu: s1 = ’((1 2) (3 4 5) ...), s2 = ’((2 3) (1 4 5) ...), rezultat = ’((2)
(4 5) ...)
Solut, ie:
(define result
(stream-zip-with (lambda (L1 L2) (filter (lambda (e) (member e L1)) L2))
,→ s1 s2))
5. Sintetizat, i ı̂n Haskell, pas cu pas, tipul funct, iei f:
f x y = f (y, y) [x]
Solut, ie:
f :: a -> b -> c
x :: a
y :: b
a = (b, b)
b = [a]
a = ([a], [a])
eroare
6. Supraı̂ncărcat, i ı̂n Haskell operatorul de comparat, ie pe liste, astfel ı̂ncât o listă să fie mai
mică sau egală cu alta, dacă toate elementele din prima listă sunt mai mici sau egale cu
toate elementele din a doua. Spre exemplu, [2, 3, 1] <= [5, 4, 3], dar nu avem că
[2, 4] <= [3, 5].
Solut, ie:
7. Folosit, i pentru scriere NOT(), AND s, i OR ca operatori logici s, i ORICARE s, i EXISTĂ drept cuantifi-
catori. Scriet, i cu caps ca să nu existe confuzii cu limbajul obis, nuit. Putet, i prescurta numele
predicatelor.
Considerăm proverbul ”Cine fură azi un ou, mâine va fura un bou.”, s, i predicatele:
fură_azi(Cine, Ce).
fură_m^
aine(Cine, Ce).
bou(Ce).
ou(Ce).
a) Traducet, i proverbul ı̂n LPOI (FOL), utilizând numai predicatele ment, ionate.
b) Traducet, i propozit, ia ı̂n LPOI ı̂n formă clauzală (FNC).
Solut, ie:
8. Implementat, i predicatul mul(+Lin, -Lout) care primes, te o listă de numere ca prim argument
s, i leagă al doilea argument la lista acelor numere din prima listă care sunt divizibile cu toate
celelalte numere care le urmează.
Exemplu: mul([24, 4, 12, 6, 3, 2], X) leagă X la [24, 12, 6, 2].
Explicat, i cum funct, ionează implementarea.
Solut, ie:
check(_, []).
check(X, [H|T]) :- mod(X, H) =:= 0, check(X, T).
mul([], []).
mul([H|LIn], [H|LOut]) :- check(H, LIn), !, mul(LIn, LOut).
mul([_|LIn], LOut) :- mul(LIn, LOut).
9. Folosit, i unul sau mai multe dintre predicatele findall, forall, bagof, setof pentru a imple-
menta predicatul secondMax(+L, -X) care găses, te al doilea cel mai mare element din lista L
(care cont, ine cel put, in 2 elemente s, i nu cont, ine duplicate). Nu utilizat, i recursivitate explicită.
Explicat, i cum funct, ionează solut, ia.
Solut, ie:
10. Problema urmăres, te reprezentarea arborilor S, I-SAU s, i operat, ii de bază asupra acestora.
Un arbore S, I-SAU este un arbore următoarele caracteristici:
• nodurile care nu sunt frunze sunt de tipul S, I (AND) sau de tipul SAU (OR) s, i pot
avea oricât, i copii.
• orice nod este o etichetă care poate fi SUCCESS, FAILURE, sau UNKNOWN.
• (10p) Elaborat, i reprezentarea arborilor S, I-SAU. La nevoie, putet, i utiliza s, i alte tipuri
auxiliare.
data AndOrTree
= Undefined
• (10p) Instant, iat, i clasa Show cu tipul AndOrTree. Reprezentarea sub formă de s, ir a unui
arbore va fi de forma următoare, ı̂n care frunzele sunt reprezentate prin eticheta lor, iar
nodurile S, I s, i SAU sunt reprezentate prin tipul s, i eticheta lor:
(OR|UNKNOWN (AND|UNKNOWN FAILURE (OR|UNKNOWN UNKNOWN SUCCESS) SUCCESS)
(AND|UNKNOWN SUCCESS (OR|UNKNOWN FAILURE SUCCESS)))
instance Show AndOrTree where
show = undefined
• (10p) Implementat, i funct, ia compute care primes, te un arbore S, I-SAU s, i produce un
arbore S, I-SAU ı̂n care au fost calculate etichetele pentru noduri, după regulile:
– un nod S, I are eticheta SUCCESS dacă tot, i copiii au eticheta SUCCESS, altfel
FAILURE.
– un nod SAU are eticheta SUCCESS dacă cel put, in un copil are eticheta SUC-
CESS, altfel FAILURE.
– toate frunzele rămân nemodificate.
De exemplu, pentru arborele reprezentat ca ı̂n exemplul de la punctul anterior, rezultatul
funct, iei compute este afis, at ca:
(OR|SUCCESS (AND|FAILURE FAILURE (OR|SUCCESS UNKNOWN SUCCESS) SUCCESS)
(AND|SUCCESS SUCCESS (OR|SUCCESS FAILURE SUCCESS)))
compute :: AndOrTree -> AndOrTree
compute = undefined
Solut, ie:
-- 1
data AndOrTree
= AND Tag [AndOrTree]
| OR Tag [AndOrTree]
| Leaf Tag
data Tag = SUCCESS | FAILURE | UNKNOWN deriving (Show, Eq)
-- 2
instance Show AndOrTree where
show (AND tag children) = intern "AND" tag children
show (OR tag children) = intern "OR" tag children
show (Leaf tag) = show tag
intern t tag chd = "(" ++ t ++ "|" ++ show tag ++ concatMap ((" " ++) .
,→ show) chd ++ ")"
-- 3
getTag (AND t _) = t
getTag (OR t _) = t
getTag (Leaf t) = t
3. Scriet, i ı̂n Racket o funct, ie echivalentă cu zip din Haskell, s, tiind că
zip :: [a] -> [b] -> [(a, b)]. Folosit, i cel put, in o funct, ională.
Solut, ie:
(define (zip L1 L2) (map cons L1 L2))
5. Instant, iat, i clasa Show pentru funct, ii Haskell care iau un argument numeric, astfel
ı̂ncât afis, area unei funct, ii f va produce afis, area rezultatelor aplicării funct, iei pe
numerele de la 1 la 10. E.g. afis, area lui (+1) va produce: 234567891011.
Solut, ie:
-# LANGUAGE FlexibleInstances #- -- nu este cerut ^
ın rezolvarea din examen
instance (Enum a, Num a, Show b) => Show (a -> b) where
show f = concatMap (show . f) [1..10]
-- Enum nu este cerut ^
ın rezolvarea din examen
6. Folosit, i list comprehensions pentru aproduce fluxul listelor formate din primii 5
multipli ai fiecărui număr natural:
[[1,2,3,4,5],[2,4,6,8,10],[3,6,9,12,15],[4,8,12,16,20] ...] .
Solut, ie:
[take 5 [m | m <- [n..], mod m n == 0] | n <- [1..]]
7. Folosit, i rezolut, ia pentru a demonstra că dacă Ion este om s, i orice om are o bicicletă
atunci este adevărat că Ion are bicicletă sau Ion este bogat (folosit, i predicatele
om(X), areBicicletă(X) s, i bogat(X)).
Solut, ie:
Avem premisele: om(ion) s, i ∀x.om(x) ⇒ areBicicletă(x)
Concluzia: areBicicletă(ion) ∨ bogat(ion)
Clauzele:
(a) {om(ion)}
(b) {¬om(x) ∨ areBicicletă(x)}
(c) {¬areBicicletă(ion)} (prima parte a concluziei negate)
(d) {¬bogat(ion)} (a doua parte a concluziei negate)
(b) + (c) {x ←
− ion} →− ¬om(ion)(e)
(a) + (e) →
− clauza vidă
8. Scriet, i un predicat Prolog diff(A, B, R) care leagă R la diferent, a mult, imilor (repre-
zentate ca liste) A s, i B.
Solut, ie:
intersect(A, B, R) :- findall(X, (member(X, A), member(X, B)), R).
9. Dat fiind un s, ir de date binare, scriet, i un algoritm Markov care plasează la sfârs, itul
s, irului suma modulo 2 a bit, ilor din s, ir. Exemple: 101010110000111
→
− 1010101100001110; 100110110110 →
− 1001101101101; 100110110111 →
− 1001101101110
Solut, ie:
CheckSum; 0,1 g1
ag1 0 →− 0ag1
a01 →− 1a1
a11 →− 1a0
a→− .
→
− a0
10. Considerăm o structură de date de tip listă circulară, caracterizată de cont, inutul
său s, i de un cursor intrinsec structurii, pozit, ionat la orice moment pe un element al
listei. Avem următoarele funct, ionalităt, i:
• Structura va putea fi creată pe baza unei liste obis, nuite L; la creare cursorul
va fi init, ial pozit, ionat pe elementul care era primul element din L;
• Operat, ia get, care ı̂ntoarce elementul de la pozit, ia unde este cursorul;
• Operat, ia next, care avansează cursorul cu o pozit, ie spre dreapta;
Exemplu: avem lista circulară C, construită pe baza listei 1,2,3,1,5. Astfel:
get(C) = 1 get(next(next(next(next(C))))) = 5
get(next(C)) = 2 get(next(next(next(next(next(C)))))) = 1
Se cere implementarea ı̂n Racket, Haskell sau Prolog a celor 3 funct, ionalităt, i: cre-
area listei circulare, operat, ia get s, i operat, ia next.
Solut, ie:
Exemplu ı̂n Haskell:
circular l = concat . repeat $ l -- desfăs, urăm lista originală
get = head -- elementul curent
next = tail -- avansăm cursorul
2
Examen PP – Seria 2CC — NOT EXAM MODE
29.05.2018
atent, ie: Avet, i 2 ore · 100p pentru nota maximă · Justificat, i răspunsurile!
3. Scriet, i ı̂n Racket o funct, ie echivalentă cu unzip din Haskell, s, tiind că
unzip :: [(a, b)] -> ([a], [b]). Folosit, i cel put, in o funct, ională.
Solut, ie:
(define (unzip L) (cons (map car L) (map cdr L)))
5. Instant, iat, i clasa Show pentru funct, ii Haskell care iau un argument numeric, astfel
ı̂ncât afis, area unei funct, ii f va produce afis, area rezultatelor aplicării funct, iei pe
numerele de la 1 la 10. E.g. afis, area lui (+1) va produce: 234567891011.
Solut, ie:
-# LANGUAGE FlexibleInstances #- -- nu este cerut ^
ın rezolvarea din examen
instance (Enum a, Num a, Show b) => Show (a -> b) where
show f = concatMap (show . f) [1..10]
-- Enum nu este cerut ^
ın rezolvarea din examen
6. Folosit, i list comprehensions pentru aproduce fluxul listelor de divizori pentru nu-
merele naturale: [[1], [1, 2], [1, 3], [1, 2, 4], [1, 5], [1, 2, 3, 6] ...] .
Solut, ie:
[[d | d <- [1..n], mod n d == 0] | n <- [1..]]
7. Folosit, i rezolut, ia pentru a demonstra că dacă George este t, ăran s, i orice t, ăran are
o sapă atunci este adevărat că George este des, tept sau George are o sapă (folosit, i
predicatele t, ăran(X), areSapă(X) s, i des, tept(X)).
Solut, ie:
Avem premisele: t, ăran(george) s, i ∀x.t, ăran(x) ⇒ areSapă(x)
Concluzia: areSapă(george) ∨ des, tept(george)
Clauzele:
(a) {t, ăran(george)}
(b) {¬t, ăran(x) ∨ areSapă(x)}
(c) {¬areSapă(george)} (prima parte a concluziei negate)
(d) {¬des, tept(george)} (a doua parte a concluziei negate)
(b) + (c) {x ← − george} → − ¬t, ăran(george)(e)
(a) + (e) → − clauza vidă
9. Dat fiind un s, ir de date binare, scriet, i un algoritm Markov care plasează la sfârs, itul
s, irului suma modulo 2 a bit, ilor din s, ir. Exemple: 101010110000111
→
− 1010101100001110; 100110110110 →
− 1001101101101; 100110110111 →
− 1001101101110
Solut, ie:
CheckSum; 0,1 g1
ag1 0 →− 0ag1
a01 →− 1a1
a11 →− 1a0
a→− .
→
− a0
10. Considerăm o structură de date de tip listă circulară, caracterizată de cont, inutul
său s, i de un cursor intrinsec structurii, pozit, ionat la orice moment pe un element al
listei. Avem următoarele funct, ionalităt, i:
• Structura va putea fi creată pe baza unei liste obis, nuite L; la creare cursorul
va fi init, ial pozit, ionat pe elementul care era ultimul element din L;
• Operat, ia get, care ı̂ntoarce elementul de la pozit, ia unde este cursorul;
• Operat, ia prev, care deplasează cursorul cu o pozit, ie spre stânga;
Exemplu: avem lista circulară C, construită pe baza listei 1,2,3,1,5. Astfel:
get(C) = 5 get(prev(prev(prev(prev(C))))) = 1
get(prev(C)) = 1 get(prev(prev(prev(prev(prev(C)))))) = 5
Se cere implementarea ı̂n Racket, Haskell sau Prolog a celor 3 funct, ionalităt, i: cre-
area listei circulare, operat, ia get s, i operat, ia prev.
Solut, ie:
Exemplu ı̂n Prolog:
circular(L, LC) :- reverse(L, LC).% inversăm lista. Elementul curent este ultimul
element din L
get(LC, Current) :- LC = [Current | ] . % elementul current
next(LC, LCNew) :- LC = [Current, Rest], append(Rest, [Current], LCNew). % rotim s, i
mergem la următorul element, ca s, i cum ^
ın lista originală am fi mers la precedentul.
2
Examen PP varianta A — NOT EXAM MODE
07.06.2022
atent, ie: Avet, i 2 ore · 1-9: 10p; 10: 30p · 100p pentru nota maximă · Justificat, i răspunsurile!
6. Instant, iat, i clasa Eq pentru funct, ii Haskell care iau un argument numeric, astfel ı̂ncât două funct, ii
sunt “egale” dacă valoarea lor este egală pentru fiecare număr ı̂ntreg ı̂ntre 1 s, i 10.
Solut, ie:
instance (Num a, Enum a, Eq b) => Eq (a -> b) where
f == g = and (zipWith (==) (map f [1..10]) (map g [1..10]))
Notă: Enum a nu era cerut.
7. Construit, i ı̂n Haskell funct, ia perms :: [Char] -> [[Char]] care primes, te o listă de caractere s, i ı̂ntoarce
fluxul s, irurilor formate din aceste caractere, ı̂ncepând cu s, iruri de lungime 1. De exemplu: take 45
$ perms "abc" ı̂ntoarce ["a","b","c","aa","ba","ca", . . . ,"bc","cc","aaa","baa","caa","aba","bba",
. . . , "acc","bcc","ccc","aaaa","baaa","caaa","abaa","bbaa","cbaa"]
Solut, ie:
perms alfa = (map (:"") alfa) ++ [c:s | s <- perms alfa, c <- alfa]
Construiesc s, irurile de lungime 1, apoi celelalte s, iruri sunt s, iruri deja ı̂n flux la care adaug unul dintre
caracterele din alfaetul dat.
8. S, tiind că Cum as, terne, as, a doarme s, i că ¬doarme(Ion, bine), demonstrat, i prin metoda rezolut, iei
că Ion nu a as, ternut bine.
Solut, ie:
Avem premisele: ¬doarme(Ion, bine) s, i ∀x.∀y.asterne(x, y) ⇒ doarme(x, y)
Concluzia: ¬asterne(Ion, bine)
Clauzele:
(a) {¬doarme(Ion, bine)}
(b) {¬asterne(x, y) ∨ doarme(x, y)}
(c) {asterne(Ion, bine)} (concluzia negată)
(b) + (c) {x ← − Ion, y ← − bine} → − doarme(Ion, bine) (d)
(a) + (d) → − clauza vidă
9. Construit, i ı̂n Prolog un predicat up(+L, -LUp) care produce ı̂n LUp o listă cu următoarele proprietăt, i:
primul element din LUp este acelas, i cu primul element din lista L
următorul element din LUp este următorul element din L, mai mare decât primul.
următorul element din LUp este următorul element din L, mai mare decât anteriorul din LUp, etc.
Exemplu: up([5, 6, 3, 4, 8, 5, 9, 2], LUp) leagă LUp la [5, 6, 8, 9].
Solut, ie:
% up(+L, -LUp)
up([H|T], [H|TUp]) :- upAux(H, T, TUp).
upAux( , [], []).
% H face parte din secvent, a crescătoare:
upAux(CurrentMax, [H|T], [H|TUp]) :- H > CurrentMax, upAux(H, T, TUp).
% H nu face parte din secvent, a crescătoare:
upAux(CurrentMax, [H|T], TUp) :- H =< CurrentMax, upAux(CurrentMax, T, TUp).
Alternativ, pot evita comparat, ia din ultima regulă, dacă folosesc ! după comparat, ia din penultima
regulă.
Un Trie (un arbore de prefixe) este un arbore care stochează cuvinte, după
prefixele lor comune. De exemplu, arborele din dreapta stochează cuvintele
10. ”melc”, ”mină”, ”mică”, ”mici”, ”mac”, ”mama”, s, i “ac”. Fiecare nod, ı̂n
afară de rădăcină. cont, ine o literă. Rezolvat, i următoarele cerint, e ı̂ntr-un
limbaj la alegere dintre Racket, Haskell s, i Prolog:
a1. descriet, i structura de date pentru reprezentarea unui arbore de prefixe (ı̂n Haskell, definit, i tipul
cu data, ı̂n Racket s, i Prolog descriet, i cum structurat, i arborele folosind construct, iile oferite de limbaj.
a2. scriet, i funct, ia / predicatul emptyTrie, care construies, te un arbore de prefixe vid (care nu cont, ine
niciun cuvânt).
b1. scriet, i funct, ia / predicatul canBeFollowedBy care pentru un caracter s, i un nod ı̂ntoarce adevărat
dacă nodul are un copil cu valoarea egală cu caracterul dat. În exemplu, pentru primul nod m,
funct, ia ı̂ntoarce adevărat pentru caracterele e, s, i s, i a.
b2. scriet, i funct, ia / predicatul getSubtreeFor care pentru un caracter s, i un nod ı̂ntoarce nodul copil
al nodului dat, care are valoarea egală caracterul dat. E.g. pentru caracterul e s, i primul nod m din
exemplu, funct, ia ı̂ntoarce subarborele cu rădăcina ı̂n nodul e.
c. scriet, i funct, ia / predicatul addWord, care primes, te un cuvânt s, i un arbore de prefixe, s, i adaugă
cuvântul la arbore.
Solut, ie:
Vezi fis, ier separat
Examen PP varianta B — NOT EXAM MODE
07.06.2022
atent, ie: Avet, i 2 ore · 1-9: 10p; 10: 30p · 100p pentru nota maximă · Justificat, i răspunsurile!
6. Instant, iat, i clasa Ord pentru funct, ii Haskell care iau un argument numeric, astfel ı̂ncât o funct, ie este
“mai mică” decât alta dacă valoarea ei este mai mică decât a celeilalte funct, ii ı̂n cel put, in unul
dintre numerele ı̂ntregi ı̂ntre 1 s, i 10.
Solut, ie:
instance (Num a, Enum a, Ord b) => Ord (a -> b) where
f <= g = or (zipWith (<=) (map f [1..10]) (map g [1..10]))
Notă: Enum a nu era cerut.
7. Implementat, i ı̂n Racket fluxul ı̂n care primele 3 elemente sunt 1, 2 s, i 3, iar fiecare dintre următoarele
elemente este produsul dintre cele trei elemente anterioare.
Solut, ie:
(define (stream-zip3 f s1 s2 s3) (stream-cons (f (stream-first s1) (stream-first s2) (stream-first
s3))
(stream-zip3 f (stream-rest s1) (stream-rest s2) (stream-rest s3)) ))
(define superProducts (stream-cons 1 (stream-cons 2 (stream-cons 3
(stream-zip3 * superProducts
(stream-rest superProducts) (stream-rest (stream-rest superProducts)) ) )))) (stream->list (stream-take
superProducts 7))
8. S, tiind că Cine ı̂nvat, ă, nu moare de foame s, i că moareDe(Ion, f oame), demonstrat, i prin metoda
rezolut, iei că Ion nu ı̂nvat, ă.
Solut, ie:
Avem premisele: moareDe(Ion, f oame) s, i ∀x.invata(x) ⇒ ¬moareDe(x, f oame)
Concluzia: ¬invata(Ion)
Clauzele:
(a) {moareDe(Ion, f oame)}
(b) {¬invata(x) ∨ ¬moareDe(x, f oame)}
(c) {invata(Ion)} (concluzia negată)
(b) + (c) {x ← − Ion} → − ¬moareDe(Ion, f oame) (d)
(a) + (d) → − clauza vidă
9. Construit, i ı̂n Prolog un predicat dn(+L, -LDown) care produce ı̂n LDown o listă cu următoarele pro-
prietăt, i:
primul element din LDown este acelas, i cu primul element din lista L
următorul element din LDown este următorul element din L, mai mic decât primul.
următorul element din LDown este următorul element din L, mai mic decât anteriorul din LDown,
etc.
Exemplu: dn([5, 6, 3, 4, 8, 5, 9, 2], LDown) leagă LDown la [5, 3, 2].
Solut, ie:
% dn(+L, -LDown)
dn([H|T], [H|TDown]) :- dnAux(H, T, TDown).
dnAux( , [], []).
% H face parte din secvent, a crescătoare:
dnAux(CurrentMin, [H|T], [H|TDown]) :- H < CurrentMin, dnAux(H, T, TDown).
% H nu face parte din secvent, a crescătoare:
dnAux(CurrentMin, [H|T], TDown) :- H >= CurrentMin, dnAux(CurrentMin, T, TDown).
Alternativ, pot evita comparat, ia din ultima regulă, dacă folosesc ! după comparat, ia din penultima
regulă.
Un Trie (un arbore de prefixe) este un arbore care stochează cuvinte, după
prefixele lor comune. De exemplu, arborele din dreapta stochează cuvintele
10. ”melc”, ”mină”, ”mică”, ”mici”, ”mac”, ”mama”, s, i “ac”. Fiecare nod, ı̂n
afară de rădăcină. cont, ine o literă. Rezolvat, i următoarele cerint, e ı̂ntr-un
limbaj la alegere dintre Racket, Haskell s, i Prolog:
a1. descriet, i structura de date pentru reprezentarea unui arbore de prefixe (ı̂n Haskell, definit, i tipul
cu data, ı̂n Racket s, i Prolog descriet, i cum structurat, i arborele folosind construct, iile oferite de limbaj.
a2. scriet, i funct, ia / predicatul emptyTrie, care construies, te un arbore de prefixe vid (care nu cont, ine
niciun cuvânt).
b1. scriet, i funct, ia / predicatul countWords, care numără cuvintele stocate ı̂ntr-un arbore de prefixe.
În exemplu sunt 7 cuvinte.
b2. scriet, i funct, ia / predicatul printWords, care ı̂ntoarce o listă cu cuvintele stocate ı̂ntr-un arbore de
prefixe. Considerăm un cuvânt ca o cale de la rădăcină la o frunză. Pentru Racket s, i Prolog, folosit, i
o reprezentare a cuvintelor mai us, or de implementat, nu trebuie neapărat să fie s, iruri de caractere.
c. scriet, i funct, ia / predicatul predict, care pentru un prefix s, i un arbore de prefixe, ı̂ntoarce o listă
cu toate cuvintele care cont, in prefixul dat.
Solut, ie:
Vezi fis, ier separat
Examen PP/2CD/28.05.19 Timp: 2h Ex 1-9: câte 10p, Pb 10: 30p, pentru maxim sunt suficiente 100p/120p
1. Încercuiți aparițiile legate și subliniați aparițiile libere ale variabilelor din expresia (λx.(λy.(x y) λz.(y z)) x).
2. Pentru codul Racket de mai jos, scrieți evoluția pas cu pas a execuției lui (pow 2 5), și ilustrați stiva la fiecare pas.
(define (pow a n)
(cond ((zero? n) 1)
((odd? n) (* a (pow a (- n 1))))
(else (pow (* a a) (/ n 2)))))
(pow 2 5) []
(* 2 (pow 2 4)) [*2]
(* 2 (pow 4 2)) [*2]
(* 2 (pow 16 1)) [*2]
(* 2 (* 16 (pow 16 0))) [*16, *2]
(* 2 (* 16 1)) [*16, *2]
(* 2 16) [*2]
32 []
a) Scrieți o funcție curry care primește un predicat p și o listă L și întoarce lista elementelor x din L pentru care x
respectă și x/2 (împărțire întreagă) nu respectă p.
(define (f p)
(λ (L)
(filter (λ (x) (and (p x) (not (p (quotient x 2))))) L)))
b) Folosiți funcția de mai sus, scriind minimul necesar, pentru a extrage elementele divizibile cu 2 dar nu cu 4 ale
unei liste numbers.
((f even?) numbers)
4. Folosind interfața Racket pentru fluxuri, implementați fluxul (1), (1 1), (1 1), (1 1 1), (1 1 1), (1 1 1 1), (1 1 1 1), …
(primul element o dată, apoi fiecare element de câte 2 ori). Apoi implementați același flux folosind promisiuni,
ca și cum interfața nu ar exista.
(define f1
(let iter ((a '(1)) (b '(1 1)))
(stream-cons a (stream-cons b (iter (cons 1 a) (cons 1 b))))))
(define f2
(let iter ((a '(1)) (b '(1 1)))
(cons a (delay (cons b (delay (iter (cons 1 a) (cons 1 b))))))))
6. Folosind un list comprehension (5p), instanțiați clasa Ord pentru tipul Student de mai jos (fiecare student este
definit prin nume și o listă de triplete de forma (nume_materie, notă_materie, credite_materie)) astfel încât
studenții să fie ordonați după totalul creditelor la materii la care au obținut notă de trecere.
data Student = Student String [(String, Int, Int)] deriving (Eq, Show)
Examen PP/2CD/28.05.19 Timp: 2h Ex 1-9: câte 10p, Pb 10: 30p, pentru maxim sunt suficiente 100p/120p
7. Traduceți în FOL propoziția: “Orice mâță blândă ori doarme, ori îl zgârie pe vreun om rău.”
8. Adăugați implementarea predicatului one_bubble (care va trece o dată prin listă interschimbând elementele
vecine care sunt în ordine strict descrescătoare) la următorul cod Prolog pentru algoritmul bubble-sort:
bubble_sort(L, L) :- one_bubble(L, L), !.
bubble_sort(L, S) :- one_bubble(L, Bubbled), bubble_sort(Bubbled, S).
one_bubble([], []).
one_bubble([X], [X]).
one_bubble([X,Y|Rest], [X|Res]) :- X =< Y, !, one_bubble([Y|Rest], Res).
one_bubble([X,Y|Rest], [Y|Res]) :- one_bubble([X|Rest], Res).
9. Pentru implementarea de mai jos, spuneți în câte moduri (și care sunt acestea, din punct de vedere al legării
variabilelor) se va satisface scopul sel(Y, [X, 2, Y, 4], 2, [1, Z, Z, 4]).
sel(X, [X|List], Y, [Y|List]).
sel(X, [X0|XList], Y, [X0|YList]) :- sel(X, XList, Y, YList).
2 moduri: Y = Z, Z = 2, X = 1 ; X = 1, Z = 2 ; false.
a) Implementați un tip de date MList pentru liste ce pot conține întregi, caractere sau perechi de întregi și caractere.
b) Implementați o funcție: filter' :: Char -> MList -> MList care filtrează o MListă astfel:
Dacă primul parametru are valoarea:
- 'i', atunci filter' întoarce o MListă ce conține doar valorile întregi
- 'c', atunci filter' întoarce o MListă ce conține doar caracterele
- 'p', atunci filter' întoarce o MListă ce conține doar perechile
c) Implementați o funcție care primește o MListă și întoarce lista caracterelor conținute, dacă în MListă se află
doar caractere, sau o valoare cu semnificație de eșec - altfel. Valoarea cu semnificație de eșec nu trebuie să se
poată obține dintr-o MListă care conține doar caractere (de exemplu, [ ] nu indică un eșec cert, ci ar putea
proveni dintr-o MListă goală).
data Val = I Int | C Char | P (Int,Char) deriving Show
data MList = M [Val]
1. Folosind evaluare normală, aduceți la forma normală expresia (λx.(λy.(x y) λz.(y z)) x).
2. Pentru codul Racket de mai jos, scrieți evoluția pas cu pas a execuției lui (mul 3 3), și ilustrați stiva la fiecare pas.
(define (mul x y)
(cond ((zero? y) 0)
((odd? y) (+ x (mul x (- y 1))))
(else (+ (mul x (/ y 2)) (mul x (/ y 2))))))
(mul 3 3) []
(+ 3 (mul 3 2)) [+3]
(+ 3 (+ (mul 3 1) (mul 3 1))) [+[..], +3]
(+ 3 (+ (+ 3 (mul 3 0)) (mul 3 1))) [+3, +[..], +3]
(+ 3 (+ (+ 3 0) (mul 3 1))) [+3, +[..], +3]
(+ 3 (+ 3 (mul 3 1))) [+3, +3]
(+ 3 (+ 3 (+ 3 (mul 3 0)))) [+3, +3, +3]
(+ 3 (+ 3 (+ 3 0))) [+3, +3, +3]
(+ 3 (+ 3 3)) [+3, +3]
(+ 3 6) [+3]
9 []
a) Scrieți o funcție care primește o funcție binară f și două liste de aceeași lungime și întoarce lista aplicărilor
lui f asupra elementelor de pe aceeași poziție (ex: pentru +, ‘(1 2 3) și ‘(4 5 6) întoarce ‘(5 7 9)).
(define (fun f L1)
(λ (L2)
(map f L1 L2)))
b) Folosiți funcția de mai sus pentru a aduna ‘(1 2 3) la toate listele dintr-o listă de liste.
(map (fun + '(1 2 3)) L)
4. Implementați în Racket fluxul multiplilor unui număr n, folosind închideri funcționale, ca și cum interfața Racket
pentru fluxuri nu ar exista. Apoi obțineți (nu altfel decât prin extragere din flux) lista primelor 3 elemente din
acest flux (pentru n = 5).
(define (stream n)
(let iter ((a 0))
(cons a (λ () (iter (+ a n))))))
(let ((fives (stream 5)))
(list (car fives) (car ((cdr fives))) (car ((cdr ((cdr fives)))))))
6. Folosind o funcție implementată cu gărzi (5p), instanțiați clasa Eq pentru tipul Student de mai jos (un student este
definit prin nume și o listă de perechi de forma (nume_materie, notă_materie)) astfel încât doi studenți sunt egali
dacă au același tip de rezultat la “PP” (există 3 tipuri: nepromovat, promovat cu nota sub 10, promovat cu nota 10).
Examen PP/2CD/28.05.19 Timp: 2h Ex 1-9: câte 10p, Pb 10: 30p, pentru maxim sunt suficiente 100p/120p
data Student = Student String [(String, Int)] deriving Show
8. Folosind cut (!) pentru evitarea calculelor inutile (5p), implementați în Prolog predicatul switchUntilZero(?List1,
?List2) astfel încât List2 are aceleași elemente cu List1, cu excepția că până la întâlnirea unui eventual element 0
toate a-urile se transformă în b-uri și b-urile în a-uri.
?- switchUntilZero([a,b,1,d,b,0,a,b], R). --- R = [b, a, 1, d, a, 0, a, b].
?- switchUntilZero(R, [a,b,c,d,b,a,b]). --- R = [b, a, c, d, a, b, a].
other(a,b). other(b,a).
switchUntilZero([], []).
switchUntilZero([0|Rest], [0|Rest]) :- !.
switchUntilZero([X|Rest], [Y|Res]) :- other(X,Y), !, switchUntilZero(Rest, Res).
switchUntilZero([X|Rest], [X|Res]) :- switchUntilZero(Rest, Res).
9. Pentru implementarea de mai jos, spuneți în câte moduri (și care sunt acestea, din punct de vedere al legării
variabilelor) se va satisface scopul pred([1, 2, 3, X], S).
pred(L, S) :- append(_, B, L), append(S, _, B), S = [_,_|_].
6 moduri: S = [1, 2] ; S = [1, 2, 3] ; S = [1, 2, 3, X] ; S = [2, 3] ;
S = [2, 3, X] ; S = [3, X] ; false.
a) (10p) Definiți tipul de date polimorfic “coadă” de elemente de un tip oarecare. O coadă va fi reținută sub
forma a 2 stive (una de in, în care adăugăm, și una de out, din care scoatem (când se golește, vărsăm stiva de
in în stiva de out, astfel încât să se respecte în continuare principiul FIFO)).
b) (20p) Pentru tipul de mai sus, furnizați signaturile (4p) și implementarea (16p) următorilor operatori:
- isEmpty care întoarce True pentru coada goală, altfel False
- top care întoarce elementul de la începutul cozii
- del care scoate elementul de la începutul cozii (întoarce coada fără acesta)
- ins care introduce un nou element în coadă (evident, la sfârșit)
data Queue a = Q [a] [a] deriving Show
1. Dați exemplu de o λ-expresie care conține 2 variabile x și y, astfel încât x are 2 apariții legate și una liberă, iar y are o
apariție legată și una liberă.
2. In Racket, folosind recursivitate pe coadă, implementați funcția n-times-n care primește un parametru n și întoarce o
listă care conține de n ori valoarea n. (ex: (n-times-n 4) => ‘(4 4 4 4)). (7p)
Ilustrați parțial (primele 3 apeluri recursive pe coadă) evoluția pas cu pas pentru (n-times-n 10). În cazul în care
folosiți o funcție ajutătoare (sau un named let), atunci veți ilustra evoluția acesteia (acestuia). (3p)
Soluție:
(define (n-times-n n) (n-times-n 4) =>
(let loop ((i n) (acc '())) (loop 4 ‘()) =>
(if (zero? i) (loop 3 ‘(4)) =>
acc (loop 2 ‘(4 4)) …
(loop (- i 1) (cons n acc)))))
Barem:
a) 2p - funcție ajutătoare sau named let cu parametri corespunzători
1p - condiție de oprire corectă
1p - întoarce acc pe cazul de bază
3p - apel recursiv cu parametri actualizați corect
b) câte 1p pentru fiecare apel
3. În Racket, fără a folosi recursivitate explicită, scrieți o funcție curry care primește o listă de funcții și o listă de
argumente și întoarce lista rezultatelor aplicării fiecărei funcții din prima listă pe argumentul de pe poziția
corespunzătoare în a doua listă. (prima funcție pe primul argument, a doua pe al doilea, etc.) (7p)
Apelați corespunzător această funcție pe o primă listă care conține funcțiile list, odd? și null?, respectiv o a doua listă
care conține valorile ‘(1), 2 și ‘(3) (2p) și precizați ce se obține în urma apelului. (1p)
Soluție:
(define (applications funcs)
(λ (args)
(map (λ (f a) (f a)) funcs args)))
((applications (list list odd? null?)) '((1) 2 (3))) => (((1)) #f #f)
Barem:
a) 3p - forma curry pentru cei 2 parametri
2p - map sau fold cu argumente corespunzătoare (ca număr și semnificație)
2p - funcție care ia f și a din cele 2 liste și calculează (f a) (sau adaugă (f a) în acc, la fold)
b) 1p - apel corespunzător formei curry
0.5p - listele construite cu o metodă corectă (funcția list sau quote unde sunt doar valori numerice)
0.5p - conținut corect liste
c) 1p - rezultat corect
4. Folosind interfața Racket pentru fluxuri, implementați fluxul x, x^2, x^3, x^4 … etc. (5p)
Folosiți-vă de această implementare pentru a implementa fluxul de liste (2 3), (4 9), (8 27), (16 81) … etc. (5p)
5. Implementați funcția de la exercițiul 3 în Haskell (cu sau fără recursivitate explicită). (3p)
Sintetizați tipul acestei funcții (nu sunt necesare explicații formale, dar sunt necesare explicații). (5p)
Apelați funcția pe o primă listă care conține funcțiile odd și null și o a doua listă care conține argumentele 2 și [3] (1p)
și precizați ce se obține în urma apelului. (1p)
Soluție:
a) applications funcs args = zipWith (\f a -> f a) funcs args
b) (1) zipWith :: (a -> b -> c) -> [a] -> [b] -> [c] (tipul funcției folosită de zipWith corespunde tipurilor elementelor listelor)
(2) \f a -> f a :: (t1 -> t) -> t1 -> t (f se aplică pe a => are un input de tipul lui a, funcția mare întoarce (f a) deci același
tip cu ce întoarce f)
din (1),(2) => a = (t1 -> t), b = t1, c = t
=> applications :: [t1 -> t] -> [t1] -> [t] (applications primește ultimele 2 argumente ale lui zipWith și întoarce ce
întoarce zipWith)
c) applications [odd, null] [2, [3]] => eroare întrucât listele nu sunt omogene (conțin elemente de tipuri diferite)
Barem:
a) 1p - luarea unui f și unui a și realizarea calculului f a
2p - zipWith sau apel recursiv cu argumente corecte (cu 0.5p pt cazul de bază, dacă se rezolvă recursiv)
b) 2p - explicație tip listă de funcții
1p - explicație tip listă de argumente
1p - explicație tip listă de rezultate
1p - explicație coincidență tip între inputul funcțiilor și argumente, între outputul funcțiilor și rezultate
c) 1p - apel scris corect
1p - semnalare eroare (explicată corect sau neexplicată, se scad 0.5p pentru eroare explicată eronat)
6. Fie definițiile următoare ale tipurilor Card (pentru cărți de joc) și Value (pentru valoarea asociată unei cărți):
data Card = C2 | C3 | C4 | C5 | C6 | C7 | C8 | C9 | C10 | J | Q | K | A deriving Show
data Value = Only Int | Either Int Int deriving Show
Definiți clasa Valuable caracterizată de o singură funcție value care primește o valoare a tipului membru al clasei și
întoarce o valoare de tip Value asociată acesteia. (3p)
Adăugați tipul Card la clasa Valuable, astfel încât cărților mici (de la 2 la 9) să li se asocieze propria lor valoare,
cărților 10, J, Q, K să li se asocieze valoarea 10, iar asului (A) să i se asocieze fie valoarea 1, fie valoarea 11. (7p)
Soluție:
class Valuable t where
value :: t -> Value
7. Demonstrați că {a, a ⇒ b, b ⇒ c} ⊨ c în două moduri: prin rezoluție (5p), respectiv cu tabele de adevăr (5p).
Soluție:
a) Cele 3 premise în formă clauzală: Rezultate ale aplicării rezoluției:
(1) {a} (4) {b} (din 1, 2)
(2) {¬a, b} (5) {c} (din 3, 4)
(3) {¬b, c}
Obs: se acceptă demonstrat așa sau prin reducere la absurd, introducând ¬c și ajungând la rezolventul vid.
b) a b c a⇒b b⇒c
T T T T T Rândul marcat este singurul care satisface premisele
T T F T F {a, a ⇒ b, b ⇒ c}, și se observă că acesta satisface și concluzia c.
T F T F T
T F F F T
….
(rândurile cu a = F oricum nu interesează pentru că nu satisfac premisele)
Barem:
a) 2p - transformarea implicațiilor în forma clauzală
3p - secvența de rezoluții care duce la {c}
b) 3p - construirea tabelei de adevăr total sau parțial cu explicația de ce restul nu contează
1p - identificarea rândurilor care satisfac premisele
1p - observația că acestea satisfac și c
8. Implementați, în Prolog, predicatul flatten care primește o listă de atomi și/sau liste (cu orice nivel de imbricare) și
întoarce o listă care conține toți atomii din lista inițială. (ex: flatten([a,[b,[c],[[d]],[],[e]]], F) => F = [a, b, c, d, e].)
Soluție:
flatten([], []).
flatten([[]|Rest], Res) :- !, flatten(Rest, Res).
flatten([[X|R]|Rest], Res) :- !, flatten([X|R], Aux1), flatten(Rest, Aux2), append(Aux1,
Aux2, Res).
flatten([X|Rest], [X|Res]) :- flatten(Rest, Res).
Barem:
1p - cazul de bază
2p - primul element listă vidă (patterns, apel recursiv)
4p - primul element listă nevidă (patterns, flatten, flatten, append)
2p - primul element atom (patterns, apel recursiv)
1p - reguli mutual exclusive
9. Se dă un graf descris prin fapte Prolog de tip nod/1 și arc/2. Folosind un metapredicat, determinați lista tuturor
perechilor de 2 noduri distincte între care există un drum de lungime 3 (3 arce). Lista nu va conține duplicate. Drumul
poate conține același nod de mai multe ori, doar nodul inițial și cel final trebuie să fie diferite.
Barem:
1p - metapredicat cu template, goal, bag
Examen PP/2CD/10.06.22 Timp: 2h Ex 1-9: câte 10p, Pb 10: 30p, pentru maxim sunt suficiente 100p/120p
1p - template pereche
3p - identificare drum de 3 arce (cu corespondența variabilelor între ele și cu cele din template)
1p - X \= Y
2p - lista nu conține duplicate (setof sau findall((X,Y), (nod(X), nod(Y), once((arc(X,Z), arc(Z,T), arc(T,Y), X \= Y))), L))
2p - rezultat sub formă de o singură listă, nu satisfaceri succesive ale unui scop (Z^T^ sau findall ca mai sus)
10. Vom folosi tipurile Card și Value definite la exercițiul 6 (puteți presupune că exercițiul 6 este deja rezolvat, și că
există funcția value care asociază fiecărei cărți valoarea acesteia) pentru a modela un joc de Blackjack. Pentru aceasta,
ne interesează doar colecțiile de cărți pentru care suma valorilor cărților este maxim 21.
a) Implementați funcția correctValue :: Value -> Maybe Value care primește o valoare de tip Value din care caută să
păstreze doar întregii care nu depășesc numărul 21. (ex: correctValue (Either 12 22) => Just (Only 12)) (10p)
b) Implementați funcția handValue :: [Card] -> Value care primește o listă de cărți și calculează suma valorilor cărților
din listă. Dacă în listă apar unul sau mai mulți ași (A), atunci rezultatul va fi de tip Either suma1 suma2, unde suma1 este
calculată pentru cazul când toți așii valorează 1, iar suma2 este calculată pentru cazul când un as valorează 11 și ceilalți
valorează 1. (Nu are sens ca mai mai mult de un as să valoreze 11, pentru că suma ar depăși 21). (ex: handValue
[A,A,J,C9] => Either 21 31) (15p)
c) Implementați point free funcția correctHandValue :: [Card] -> Maybe Value care primește o listă de cărți și
calculează suma valorilor cărților din listă, cu corecția de la punctul a) deja aplicată, astfel încât să rămână doar sumele
utile. (ex: correctHandValue [A,A,J,C9] => Just (Only 21)) (5p)
Barem:
a) 2p - Only s, s > 21 (peste tot, cele 2p se împart: pattern 0.5, condiție 0.5,
2p - Only s, altfel retur 1 (din care 0.5 pt aplicare Just, acolo unde este cazul))
2p - Either, ambele > 21
2p - Either, una > 21
2p - Either, ambele bune
b) 3p - valoare mână goală (dacă se folosește pattern matching, punctele se împart similar cu a))
6p - valoare mână fără ași
6p - valoare mână cu ași
c) 5p – compunerea funcțiilor de mai sus (din care 2p ordinea corectă)
1.
a)
Obs: În rezolvarea acestui subiect, puteți folosi semnul \
(backslash) în loc de λ (lambda).
b)
Obs: În rezolvarea acestui subiect, puteți folosi semnul \
(backslash) în loc de λ (lambda).
c)
Obs: În rezolvarea acestui subiect, puteți folosi semnul \
(backslash) în loc de λ (lambda).
d)
Obs: În rezolvarea acestui subiect, puteți folosi semnul \
(backslash) în loc de λ (lambda).
Soluții 1:
Barem:
- reducere λn.restul: 4p
- reducere λf interior: 3p
- reducere λx interior: 3p
Primul pas trebuie efectuat separat. În caz contrar, reducerea nu se
punctează.
Dacă pasul 2 este combinat cu pasul 3, se scad 2 puncte.
(SUCC 0)
(λn.λf.λx.(f ((n f) x)) λf.λx.x) ->b
λf.λx.(f ((λf.λx.x f) x)) ->b
λf.λx.(f (λx.x x)) ->b
λf.λx.(f x)
(SUCC 1)
(λn.λf.λx.(f ((n f) x)) λf.λx.(f x)) ->b
λf.λx.(f ((λf.λx.(f x) f) x)) ->b
λf.λx.(f (λx.(f x) x)) ->b
λf.λx.(f (f x))
(SUCC 2)
(λn.λf.λx.(f ((n f) x)) λf.λx.(f (f x))) ->b
λf.λx.(f ((λf.λx.(f (f x)) f) x)) ->b
λf.λx.(f (λx.(f (f x)) x)) ->b
λf.λx.(f (f (f x)))
(SUCC 3)
(λn.λf.λx.(f ((n f) x)) λf.λx.(f (f (f x)))) ->b
λf.λx.(f ((λf.λx.(f (f (f x))) f) x)) ->b
λf.λx.(f (λx.(f (f (f x))) x)) ->b
λf.λx.(f (f (f (f x))))
---------------------------------------------------------------------
---------------------------------
2.
a)
Pentru funcția f de mai jos:
(define (f L)
(if (or (null? L) (null? (cdr L)))
L
(cons (max (car L) (cadr L))
(f (cddr L)))))
i) Argumentați ce tip de recursivitate (stivă/coadă) folosește f.
(1p tipul, 2p argumentația)
ii) Spuneți în cuvinte ce calculează f. (2p)
iii) Definiți funcția ff, care are același efect cu f, dar folosește
celălalt tip de recursivitate. (5p)
Soluție 2a:
i) stivă - apelul recursiv nu e în poziție finală.
ii) se parcurg elementele 2 câte 2 și se reține maximul din fiecare
pereche; pentru o listă cu număr impar de elemente, ultimul element
este copiat ca atare în rezultat.
iii)
b)
Pentru funcția f de mai jos:
(define (f L)
(cond ((or (null? L) (null? (cdr L))) L)
((equal? (car L) (cadr L)) (f (cdr L)))
(else (cons (car L) (f (cdr L))))))
i) Argumentați ce tip de recursivitate (stivă/coadă) folosește f.
(1p tipul, 2p argumentația)
ii) Spuneți în cuvinte ce calculează f. (2p)
iii) Definiți funcția ff, care are același efect cu f, dar folosește
celălalt tip de recursivitate. (5p)
Soluție 2b:
i) stivă - al doilea apel recursiv nu e în poziție finală.
ii) se elimină duplicatele consecutive din listă.
iii)
c)
Pentru funcția f de mai jos:
(define (f L x)
(cond ((null? L) x)
((null? (cdr L)) (+ x (car L)))
((equal? (car L) (cadr L)) (f (cdr L) x))
(else (f (cdr L) (+ x (car L))))))
i) Argumentați ce tip de recursivitate (stivă/coadă) folosește f.
(1p tipul, 2p argumentația)
ii) Spuneți în cuvinte ce calculează f. (2p)
iii) Definiți funcția ff, care are același efect cu f, dar folosește
celălalt tip de recursivitate. (5p)
Soluție 2c:
i) coadă - toate apelurile recursive sunt în poziție finală.
ii) se adună elementele din listă, pentru duplicatele consecutive
luându-se în calcul o singură valoare.
iii)
d)
Pentru funcția f de mai jos:
(define (f L x)
(cond ((null? L) x)
((> (car L) x) (f (cdr L) x))
(else (+ (car L) (f (cdr L) x)))))
i) Argumentați ce tip de recursivitate (stivă/coadă) folosește f.
(1p tipul, 2p argumentația)
ii) Spuneți în cuvinte ce calculează f. (2p)
iii) Definiți funcția ff, care are același efect cu f, dar folosește
celălalt tip de recursivitate. (5p)
Soluție 2d:
i) stivă - al doilea apel recursiv nu e în poziție finală.
ii) se adună o valoare x cu toate elementele din listă mai mici sau
egale cu x.
iii)
ex:
(odd-pos '(5 6 5 4 3 4 5)) => '(6 4 4)
Soluție 3a:
; cu map + filter
(define (odd-pos L)
(let ((p (map cons L (range (length L)))))
; 4p împerechere element-poziție (2p folosire map, nu un zip
inventat)
(map car ; 2p extragerea elementelor listei din perechi
(filter (λ(x) (odd? (cdr x))) p))))
; 4p filtrarea pozițiilor impare (2p predicat corect)
; cu fold
(define (odd-pos2 L)
(reverse ; 2p ordine corectă
(second ; 2p rezultat corect (doar elementele cerute, fără alte
informații)
(foldl (λ (x acc)
; 1p ordine corectă pt argumentele funcției de la fold
(if (first acc)
; 2p metodă de a distinge între pozițiile pare și impare
(list #f (cons x (second acc)))
b)
Atenție: Acest exercițiu nu se punctează decât dacă este rezolvat
fără a folosi recursivitate
explicită (deci nici letrec sau named let). Soluțiile explicit
recursive se punctează cu 0.
ex:
(alternate '(1 2 3 4 5 6 7) add1 sub1) => '(2 1 4 3 6 5 8)
Soluție 3b:
; cu map
(define (alternate L f1 f2)
(let* ((l (length L))
(fL (flatten (make-list l (list f1 f2)))))
; 4p crearea listei de funcții (2p aplatizare cu flatten sau apply)
(map (λ (f x) (f x)) (take fL l) L)))
; 4p aplicarea listei de funcții pe L
; 2p lungimea corectă a listei de funcții
; cu fold
(define (alternate2 L f1 f2)
(reverse ; 2p ordine corectă
(second ; 2p rezultat corect (doar elementele cerute, fără alte
informații)
(foldl (λ (x acc)
; 1p ordine corectă pt argumentele funcției de la fold
(if (first acc)
; 2p metodă de a distinge între pozițiile pare și impare
(list #f (cons (f1 x) (second acc)))
; 1p noul acc pe cazul aplicării f1
(list #t (cons (f2 x) (second acc)))))
; 1p noul acc pe cazul aplicării f2
(list #t '())
; 1p acc inițial
L))))
c)
Atenție: Acest exercițiu nu se punctează decât dacă este rezolvat
fără a folosi recursivitate
explicită (deci nici letrec sau named let). Soluțiile explicit
recursive se punctează cu 0.
ex:
(compare-seq '(1 1 2 1 4 3)) => '(EQ LT GT LT GT) (explicație: primul
EQ descrie relația dintre elementele de pe primele 2 poziții, apoi LT
pentru elementele de pe pozițiile 2 și 3, apoi GT pentru elementele
de pe pozițiile 3 și 4, etc.)
Soluție 3c:
(define (compare-seq L)
(let* ((l (length L))
(L1 (take L (- l 1)))
; 2p crearea listei fără ultimul element
(L2 (cdr L)))
; 2p crearea listei fără primul element
; 4p aplicarea funcției binare pe cele 2 liste
; 2p funcția binară a lui map
(map (λ (x y) (cond ((= x y) 'EQ)
((< x y) 'LT)
((> x y) 'GT))) L1 L2)))
d)
Atenție: Acest exercițiu nu se punctează decât dacă este rezolvat
fără a folosi recursivitate
explicită (deci nici letrec sau named let). Soluțiile explicit
recursive se punctează cu 0.
ex:
(eq-sums? '(1 4 2 5 3 6)) => #t (explicație: 1+6 = 4+3 = 2+5)
(eq-sums? '(1 4 5 1 3 6)) => #f (explicație: 1+6 = 4+3 != 5+1)
Soluție 3d:
(define (eq-sums? L)
(or (null? L) ; 0p cazul de listă vidă
(let ((R (reverse L))) ; 2p inversarea listei
(null? (filter (λ (x) (not (equal? x (+ (car L) (car R)))))
; 2p predicat corect filter
; 2p prelucrare filter (aici null?)
(map + L R))))))
; 4p adunarea celor 2 liste
Subiectul 4
===========
Varianta 1
----------
Rezolvare:
(define multiples
(stream-cons naturals
(stream-map (λ (s) (stream-zip-with + s naturals))
multiples)))
Barem:
Varianta 2
----------
Rezolvare:
(define pyramids
(stream-cons '(1)
(stream-map (λ (L)
(append '(1) (map add1 L) '(1)))
pyramids)))
Barem:
Varianta 3
----------
Rezolvare:
(define (partial-unions sets)
(letrec
([out
(stream-cons
'()
(stream-zip-with (λ (union set)
(append union
(filter (λ (x)
(not (member x union)))
set)))
out
sets))])
out))
Barem:
Varianta 4
----------
find ((7,x) : _) = x
find (_ : pairs) = find pairs
Rezolvare:
find lst
find ((1+2, 3+4) : ...)
find ((3, 3+4) : ...)
find ((3+4, 5+6) : ...)
find ((7, 5+6) : ...)
5+6
11
Barem:
2p: întâi se evaluează doar 1+2 la 3
2p: apoi se evaluează doar 3+4 la 7
2p: se extrage 5+6
2p: se evaluează 5+6 la 11
2p: nu se evaluează altceva
Subiectul 5
===========
Varianta 1
----------
f x y = head x y
Rezolvare:
f :: a -> b -> c
x :: a
y :: b
head :: [d] -> d
a = [d]
head x = d
d = e -> g
e = b
c = g
f :: [b -> g] -> b -> g
Barem
Varianta 2
----------
Sintetizați, pas cu pas, tipul următoarei funcții în Haskell:
Rezolvare:
f :: a -> b -> c
x :: a
y :: b
fst :: (d, e) -> d
snd :: (d, e) -> e
a = (d, e)
fst x :: d
snd x :: e
map :: (g -> h) -> [g] -> [h]
e = g -> h
b = [g]
c = [h]
d = h
f :: (h, g -> h) -> [g] -> [h]
Barem
Varianta 3
----------
f :: a -> b -> c
x :: a
y :: b
tail :: [d] -> [d]
a = [d]
tail x :: [d]
fst :: (e, g) -> e
snd :: (e, g) -> g
b = (e, g)
fst y :: e
snd y :: g
e = [d]
g = [d] (din aceeași listă cu elemente de tipul e)
f :: [d] -> ([d], [d]) -> [[d]]
Barem
Varianta 4
----------
f x y = (f x, f y)
Rezolvare:
f :: a -> b -> c
x :: a
y :: b
a = b
f x :: a -> c
f y :: a -> c
c = (a -> c, a -> c)
Eroare de sinteză, întrucât expresia de tip din dreapta conține
strict variabila c.
Barem
Subiectul 6
===========
Varianta 1
----------
Rezolvare:
Barem:
1p Show (a -> b)
1p Num a
1p Show a
1p Show b
6p implementare show
4p valorile funcției
2p punctele efective
Rezolvare:
Barem:
1p Ord (a -> b)
1p Num a
1p Ord b
7p implementare (<=)
2p aplicare f pe cele 100 de puncte
2p aplicare g pe cele 100 de puncte
3p comparare valoare cu valoare
Varianta 3
----------
Rezolvare:
Varianta 4
----------
Rezolvare:
Barem:
Subiectul 7
===========
Varianta A
----------
De exemplu:
Barem:
Varianta B
----------
Soluție:
De exemplu:
Barem:
Varianta C
----------
Soluție:
De exemplu:
¬P(x, y) V ¬Q(z, t, x) V R(t, z, y)
¬R(Aurel, Ionuț, Pachet) // concluzia negată
---------------------------- t <- Aurel, z <- Ionuț, y <- Pachet
¬P(x, Pachet) V ¬Q(Ionuț, Aurel, x)
Q(Ionuț, Aurel, Carioca)
--------------------------- x <- Carioca
¬P(Carioca, Pachet)
P(Carioca, Pachet)
-------------------
clauza vidă
Barem:
Varianta D
----------
Soluție:
De exemplu:
Barem:
Subiectul 8
===========
Varianta A
----------
Soluție:
identify([], []).
identify([L|LL], [(H, L) | LLOut]) :-
sort(L, L), !, reverse(L, [H|_]), identify(LL, LLOut).
identify([[H|T]|LL], [(H,[H|T])|LLOut]) :- identify(LL, LLOut).
Varianta B
----------
Soluție:
Varianta C
----------
Soluție:
aux2([], _, []).
aux2([H|T], C, [H|ST]) :- H < C, !, aux2(T, H, ST).
aux2([_|T], C, ST) :- aux2(T, C, ST).
subDown([H|T], [H|ST]) :- aux2(T, H, ST).
Varianta D
----------
Soluție:
aux([], _, []).
aux([H|T], C, [H|ST]) :- H > C, !, aux(T, H, ST).
aux([_|T], C, ST) :- aux(T, C, ST).
subUp([H|T], [H|ST]) :- aux(T, H, ST).
Subiectul 9
===========
Varianta A
----------
Implementați folosind metapredicate (forall, findall, bagof, setof),
și fără recursivitate explicită, predicatul counts(+List, -ListPlus),
care primește în List o listă de liste de elemente oarecare, și leagă
ListPlus o listă de liste, fiecare element LP din ListPlus fiind
bazat pe o listă L din List: primul element este numărul elementelor
*diferite* din L, iar restul elementelor sunt elementele din L.
Exemplu:
Sol:
counts(List, ListPlus) :-
findall([Len|L],
(
member(L, List),
setof(E, member(E, L), Es),
length(Es, Len)
),
ListPlus).
Barem:
Numărare elemente unice: 3p
Aplicare mecanism numărare elemente unice pe fiecare listă: 4p
Asamblare corectă: 3p
Varianta B
----------
Exemplu:
Pentru lista List = [[a], [b, 1, 2, 3, 4, 3], [c, x, y, x, y], [d,
1], [e, 1,1,1,1,1,1,1,1]]
Sol:
Barem:
Găsire elemente unice: 4p
Verificarea numărului de elemente unice: 2p
Asamblarea soluției: 3p
Varianta C
----------
Exemplu:
index([8, 1, 2, 3, 1, 2, 5, 4, 7, 6, 2, 5], X) leagă X la [(1, 2),
(2, 3), (3, 1), (4, 1), (5, 2), (6, 1), (7, 1), (8, 1)]
Sol:
index(List, Index) :-
setof((E, Times),
L^(
member(E, List),
findall(X, (member(X, List), E = X), L),
length(L, Times)
),
Index).
sau
index(List, Index) :-
setof(E, member(E, List), Es),
findall((E, Times),
( member(E, Es),
findall(X, (member(X, List), E = X), L),
length(L, Times)
),
Index).
Barem:
Găsirea elementelor fără duplicate: 4p
Numărul de apariții pentru fiecare element: 2p
Asamblarea soluției: 2p
Varianta D
----------
Exemplu:
Sol:
singles(List, Singles) :-
setof(E,
L^( member(E, List),
findall(X, (member(X, List), E = X), L),
length(L, 1)
),
Singles).
Barem:
Verificarea dacă un element este unic: 4p
Verificarea unicității pentru toate elementele: 4p
Asamblarea soluției: 2p