Documente Academic
Documente Profesional
Documente Cultură
(define (getMax L)
(car(sort L >)))
;; MapAnd
(define (MyAndMap L)
(foldl (lambda (a b) (and a b)) #t L))
Haskell
-- Tipuri funcții uzuale
-- Flux de divizori
flux1 = [[d | d <- [1..n], mod d n == 0] | n <- [1..]]
Prolog
%% Concatenarea a 2 liste în Prolog
intersection (A, B, Result) :- findall (X, member(X, A), member(X, B), Result).
predicat(L, A, B, N) :- findall (X, (member(X, L), X > A, X < B), S), length(S, N).
%% Implementare map f
count(X, [H|T], N) :-
X == H,
count(X, T, N2),
N is N2 + 1.
count(X, [Y|T], N) :-
X \= Y,
count(X, T, N).
Exemplu cu Omega:
(λy.((λx.λy.x y) Ω)λx.λy.y)
Solutie:
(λy.((λx.λy.x y) Ω)λx.λy.y)→((λx.λy.x λx.λy.y) Ω)
→(λy.λx.λy.yΩ)→λx.λy.y
Racket:
Lab 1:
;; Fie următoarele axiome pentru obținerea reprezentării unui număr
natural
;; în baza b (cu [] = lista vidă și ++ =
concatenare).
;; num->base(0,b) = [ ] ; pt n=0
;; num->base(n,b) = num->base(n div b, b) ++ [ n mod b ] ; pt n>0
;; Implementați funcția corespunzătoare în Racket:
(define (num->base n b)
(if (zero? n)
'()
(append (num->base (quotient n b) b) (list (modulo n b)))))
;; Inversul unei liste
(define (rev L)
(if (null? L)
'()
(append (rev (cdr L)) (list (car L)))))
; Să se găsească cea mai lungă porțiune continuă care este palindrom, dintr-un număr, în baza
10.
(define (num->list n)
(if (zero? n)
'()
(append (num->list (quotient n 10)) (list (modulo n 10)))))
(define (longest-palindrome n)
(if (palindrome? (num->list n))
n
(max (longest-palindrome (modulo n (expt 10 (sub1 (length (num->list n))))))
(longest-palindrome (quotient n 10)))))
Lab 2:
;; Exercitiul 1 - folosirea functiei trace pentru a intelege mai bine desfasurarea recursivitatii
(define (factorial n)
(if (= n 1)
1
(* n (factorial (- n 1)))))
(define (fib n)
(cond ((= n 0) 0)
((= n 1) 1)
(else (+ (fib (- n 1))
(fib (- n 2))))))
(define (fib2 n)
(fib-iter 1 0 n))
(define (fib-iter a b count)
(if (= count 0)
b
(fib-iter (+ a b) a (- count 1))))
(define (sum-list L)
(sum-list-iter 0 L))
(define (sum-list-iter sum L)
(if (null? L)
sum
(sum-list-iter (+ sum (car L)) (cdr L))))
(define (len L)
(len-iter 0 L))
(define (len-iter result L)
(if (null? L)
result
(len-iter (+ 1 result) (cdr L))))
;; Implementare append
(define (app A B)
(app-iter B (reverse A)))
(define (app-iter B Result)
(if (null? B)
(reverse Result)
(app-iter (cdr B) (cons (car B) Result))))
(exercițiul 1 : 1 punct)
(define (rev L)
(let loop ((pend L)
(res '()))
(if (null? pend)
res
(loop (cdr pend) (cons (car pend) res)))))
(define (remove-duplicates-right L)
(cond
[(= (length L) 0) '()]
[(if (member (car L) (cdr L)) (remove-duplicates-right (cdr L))
(append (list (car L)) (remove-duplicates-right (cdr L))))]
)
)
[
(cons (car ys) (merge-lists xs (cdr ys)))]))
(define (mergesort L)
(cond
[(or (null? L) (null? (cdr L))) L]
[(null? (cddr L))
(merge-lists (list (car L)) (cdr L))]
[#t
(let ([x (ceiling (/ (length L) 2))])
(merge-lists (mergesort (take L x))
(mergesort (drop L x))))]))
Lab 3:
(define (uncurry->curry f)
(lambda (x)
(lambda (y)
(f x y))))
(define (curry->uncurry f)
(λ (x y)
((f x) y)
))
(exercițiul 3 : 2 puncte)
;; Reimplementați funcțiile remove-duplicates-left, remove-duplicates-right, overlay-> și overlay<-
;; de la laboratorul 2, fără a folosi explicit recursivitatea, ci utilizând
;; funcționale.
;; Acolo unde este cazul, folosiți funcții anonime.
(define (remove-duplicates-left L)
(foldr (lambda (x y) (cons x (filter (lambda (z) (not (equal? x z))) y))) empty L))
(define (remove-duplicates-right L)
(foldl (lambda (x y) (cons x (filter (lambda (z) (not (equal? x z))) y))) empty L)
)
(define (f matrix)
(if (null? matrix)
'()
(append (list (overlay-> empty-image (car matrix))) (slim-horizontal (cdr matrix)))
(exercițiul 6 : 1 punct)
;; Implementați funcția mirror care obține matricea inițială dată ca parametru vazută în oglindă.
;; Funcția trebuie implementată fără a folosi recursivitate explicit,
;; ci utilizând doar funcționale.
(define (transpose M)
(if (null? (car M))
'()
(cons (map car M)
(transpose (map cdr M)))))
;;)
[
(cons (car ys) (merge-lists xs (cdr ys)))]))
(define (mergesort L)
(cond
[(or (null? L) (null? (cdr L))) L]
[(null? (cddr L))
(merge-lists (list (car L)) (cdr L))]
[#t
(let ([x (ceiling (/ (length L) 2))])
(merge-lists (mergesort (take L x))
(mergesort (drop L x))))]))
LAB 4:
(exercițiul 1 : 1 puncte)
;; Funcția compute-square-area primește ca argument o funcție
;; ce returnează un număr, reprezentând latura unui pătrat;
;; compute-square-area trebuie să calculeze aria acelui pătrat.
;; Atenție: Aveți voie să aplicați get-length o singură dată.
;; Nu puteți folosi `exp`/`expt`
(define (compute-square-area get-length)
(let ((l (get-length)))
(* l l )))
(exercițiul 2 : 1 puncte)
;; Funcția compute-length primește ca argumente 3 funcții:
;; - get-line-segment => întoarce un segment de dreaptă.
;; - get-start-point => primește un segment de dreaptă și
;; întoarce punctul din care segmentul începe.
;; - get-end-point => primește un segment de dreaptă și
;; întoarce punctul în care segmentul se termină.
;;
;; Un punct este reprezentat printr-o pereche de numere.
;; Un segment de dreaptă este reprezentat printr-o pereche de puncte.
;;
;; compute-length trebuie să calculeze lungimea segmentului de dreaptă.
;; (distanța dintre punctul de început și punctul de sfârșit)
;; Atenție: Fiecare funcție primită drept argument trebuie aplicată o singură dată.
(define (compute-length get-line-segment get-start-point get-end-point)
(let* ((segm (get-line-segment))
(start (get-start-point segm))
(end (get-end-point segm))
(start-x (car start))
(start-y (cdr start))
(end-x (car end))
(end-y (cdr end)))
(sqrt (+ (* (- end-x start-x) (- end-x start-x)) (* (- end-y start-y) (- end-y start-y))))))
(exercițiul 3 : 1 puncte)
;; Definiți funcția distance care calculează distanța
;; dintre două puncte bazându-se pe funcția compute-length.
;; Identificați închiderea funcțională și arătați-o
;; asistentului pentru a vă puncta acest exercițiu.
(define (distance p1 p2)
(let* ((segm (cons p1 p2))
(get-segm (λ () segm))
(get-start (λ (segm) p1))
(get-end (λ (segm) p2)))
(compute-length get-segm get-start get-end)))
(exercițiul 4 : 1 puncte)
;; Fie f(x) o funcție oarecare,
;; Calculați valorile funcției f(x), a < x <= b cu pasul step.
;; Atenție: Folosiți named let.
;; Nu apelați recursiv `compute-f-with-step`.
;; Nu aveți voie să folosiți funcționale.
(define (compute-f-with-step f a b step)
(let calculate ((x a))
(if (> x b)
null
(cons (f x) (calculate (+ x step))))))
(exercițiul 5 : 1 puncte)
;; Funcția num-concat primește două numere și le concatenează.
;; ex:
;; > (num-concat 33 22)
;; 3322
;; Suprascrieți procedura `+` doar în contextul local pentru
;; a realiza concatenarea dintre două numere.
;; Hint: `string-append` concatenează două string-uri
;; Hint: Puteți folosi funcțiile `number->string` și `string->number`
(define (num-concat x y)
(let ((+ (λ (x y) (string->number (string-append (number->string x) (number->string y))))))
(+ x y)));; Nu stergeți această linie.
(exercițiul 6 : 3 puncte)
;; Definiți funcția compute-perimeter care primește un poligon reprezentat
;; printr-o listă de puncte și calculează perimetrul acestuia.
;; Atenție: Nu aveți voie să definiți funcții ajutătoare în exteriorul funcției compute-perimeter.
;; Nu aveți voie să folosiți funcționale.
;; Hint: Folosiți-vă de funcția distance
(define (compute-perimeter points)
(let perim ((current-points points))
(if (null? (cdr current-points))
(distance (car points) (car current-points))
(+ (distance (car current-points) (second current-points))
(perim (cdr current-points))))))
(exercițiul 7 : 2 puncte)
;; Se dau 3 secvențe separate printr-un separator.
;; Definiți funcția `3-sequence-max` care găsește
;; suma secvenței de sumă maximă.
;; ex:
;; (1 2 3 0 3 5 4 0 5 200) => secvența de sumă maximă este 205
;; Atenție: Nu aveți voie să folosiți fold/apply.
;; Folosiți let-values/let*-values.
;; Hint:: Uitați-vă peste splitf-at.
(define (sum-list L)
(apply + L))
LAB 5:
;; Funcții utile:
;; primește un flux și obține o listă cu primele n elemente din flux
(define (stream-take s n)
(cond ((zero? n) '())
((stream-empty? s) '())
(else (cons (stream-first s)
(stream-take (stream-rest s) (- n 1))))))
;; fluxul numerelor naturale
(define naturals
(let loop ((seed 0))
(stream-cons seed (loop (add1 seed)))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(exercițiul 6 : 2 puncte)
;; Folosiți funcția de mai sus pentru a afla cine câștigă jocul următor:
;; - 2 jucători, 1 și 2, pleacă de la un număr natural n > 0
;; - cei 2 alternează mutări, 1 mută primul
;; - o mutare a lui 1 constă în a scădea 1 din n-ul curent, dacă n e multiplu de 3, sau a scădea 3, altfel
;; - o mutare a lui 2 constă în a scădea 2 din n-ul curent, dacă n e multiplu de 4, sau a scădea 1, altfel
;; - câștigă cel care ajunge primul la n <= 0
;; NU ne interesează o soluție matematică, ci una care folosește funcția de mai sus!
(define (winner n)
(car
(stream-first
(stream-filter
(lambda (pair) (<= (cdr pair) 0))
(stream-zip-with cons
(repeat 2 1)
(play n
(lambda (n) (if (zero? (modulo n 3)) (- n 1) (- n 3)))
(lambda (n) (if (zero? (modulo n 4)) (- n 2) (- n 1)))))))))
(exercițiul 7 : 3 puncte)
;; fluxul Bell: (1), (1 2), (2 3 5), (5 7 10 15) ...
;; regula după care se generează listele din flux
;; - prima listă este (1)
;; - următoarea începe cu ultimul element din lista anterioară, apoi
;; elementul cu indice i din lista curentă este suma elementelor cu indice i-1
;; din listele curentă și anterioară (https://en.wikipedia.org/wiki/Bell_triangle)
(define (next-bell L len)
(letrec ((S1 (list->stream L))
(S2 (stream-cons (last L) (stream-zip-with + S1 S2))))
(stream-take S2 len)))
(define bell-stream
(let loop ((L '(1)) (len 2))
(stream-cons L (loop (next-bell L len) (add1 len)))))
;; BONUS
(exercițiul 8 : 1 puncte)
;; funcția curry stream-merge care interclasează 2 fluxuri sortate
;; după următoarea regulă: e1 precede pe e2 dacă (comp (f e1) (f e2))
;; ex: (stream-take ((stream-merge < sqr) naturals naturals) 10) => (0 0 1 1 2 2 3 3 4 4)
(define (stream-merge comp f)
(lambda (s1 s2)
(cond
((stream-empty? s1) s2)
((stream-empty? s2) s1)
((comp (f (stream-first s1)) (f (stream-first s2)))
(stream-cons (stream-first s1) ((stream-merge comp f) (stream-rest s1) s2)))
(else (stream-cons (stream-first s2) ((stream-merge comp f) s1 (stream-rest s2)))))))
(exercițiul 9 : 3 puncte)
;; fluxul perechilor de numere naturale sortate crescător după suma elementelor din pereche
;; rezultatul conține doar perechi (x y) cu x <= y
;; perechile cu aceeași sumă sunt sortate după primul element din pereche
;; Hint: prelucrați 2 fluxuri s1 și s2 unde inițial s1 = s2 = naturals
;; Hint: identificați o structură recursivă pe care puteți folosi stream-merge
(define natural-pairs
(let loop ((s1 naturals) (s2 naturals))
(stream-cons
(list (stream-first s1) (stream-first s2))
((stream-merge <= (lambda (p) (apply + p))) (stream-map (lambda (e2) (list (stream-first s1) e2))
(stream-rest s2))
(loop (stream-rest s1) (stream-rest s2))))))
(exercițiul 10 : 1 puncte)
;; fluxul posibilelor aruncări de 2 zaruri, sortate după suma zarurilor
;; rezultatul conține doar perechi (x y) cu x <= y
;; perechile cu aceeași sumă sunt sortate după primul element din pereche
(define dice-rolls
(let ((dice-stream (list->stream '(1 2 3 4 5 6))))
(let loop ((s1 dice-stream) (s2 dice-stream))
(if (stream-empty? s1)
empty-stream
(stream-cons
(list (stream-first s1) (stream-first s2))
((stream-merge <= (lambda (p) (apply + p))) (stream-map (lambda (e2) (list (stream-first s1)
e2)) (stream-rest s2))
(loop (stream-rest s1) (stream-rest s2))))))))
LAB 6:
1. (1p)
Implementați funcția `unzip2`
-}
unzip2 :: [(stack, b)] -> ([stack], [b])
unzip2 [] = ([], [])
unzip2 ((stack, b) : xs) = (stack : (fst (unzip2 xs)), b : (snd (unzip2 xs)))
{-
2. (1p)
Implementați, folosind obligatoriu list-comprehensions, lista tuturor numerelor prime până la n.
-}
intSqrt = floor . sqrt . fromIntegral
3. (3p)
Implementați, folosind obligatoriu list-comprehensions, operații pe mulțimi:
intersecție, diferență, produs cartezian. Utilizați ulterior funcțiile definite anterior
pentru stack reprezenta reuniunea mulțimilor.
-}
setIntersection :: Eq stack => [stack] -> [stack] -> [stack]
setIntersection stack b = [x | x <- stack, elem x b]
4. (1.5p)
Implementați o funcție ce grupează elementele egale ale unei liste în liste separate.
Funcția ar trebui să aibă același comportament cu Data.List.group:
http://zvon.org/other/haskell/Outputlist/group_f.html
-}
group2 :: Eq stack => [stack] -> [[stack]]
group2 [] = []
group2 (x : xs) =
let (equal, rest) = span (== x) xs
in (x : equal) : group2 rest
{-
5. (1.5p)
Găsiţi numărul de apariţii ale fiecărui element dintr-o listă în lista respectivă.
Rezultatul va fi returnat ca o listă de tupluri, în care primul element al perechii
va fi elementul din listă, iar al doilea element al perechii va fi numărul de apariţii în listă.
Cum rezultatul va fi similar unui dicţionar, chiar dacă un element va apărea de mai multe ori în
listă,
va trebui să fie prezent într-o singură pereche în dicţionar.
Hint: S-ar putea să aveți nevoie de funcții auxiliare. Puteți folosi "group2" de mai sus pentru
stack grupa elementele egale în liste separate şi "sort" pentru stack sorta o listă.
-}
nrOcc :: Ord stack => [stack] -> [(stack, Int)]
nrOcc = map (\ x -> ((head x), (length x))) . group2 . sort
{-
6. (2p)
Duplicaţi toate cuvintele dintr-o propoziţie.
Exemplu: Ce laborator frumos! -> Ce Ce laborator laborator frumos! frumos!
Hint: Ar putea fi utile funcţiile "concat" sau "++" pentru concatenarea cuvintelor, iar "words" si
"unwords" pentru conversia unei propoziții la o listă de cuvinte si invers.
-}
dup :: String -> String
dup = unwords . map (\w -> w ++ " " ++ w) . words
{-
7. (1p Bonus)
Verificați dacă un șir de caractere este isogramă.
Un șir este isogramă daca niciuna din literele sale nu se repetă (dar alte caractere se pot repeta).
Hint: Pe lângă funcțiile de până acum, "isLetter" si "toLower" v-ar putea ajuta în implementare.
Nu uitați că puteți afla semnătura oricărei funcții din interpretor!
-}
isIsogram :: String -> Bool
isIsogram = all (\p -> (snd p) == 1) . nrOcc . map toLower . filter isLetter
{-
8. (2p Bonus)
Determinați dacă un șir format din caracterele (, [, {, ), ], } este corect parantezat.
{-
9. (2p Bonus) Scrieți o funcție ce primește la intrare o literă și întoarce o listă sub forma unui
diamant,
formată din șiruri ce conțin literele de la 'A' pană la cea dată, astfel:
Pentru stack obține litera imediat predecesoare altei litere puteți folosi funcția "pred".
Funcția "prettyPrint" este utilă pentru vizualizarea rezultatului în forma de mai sus.
-}
diamond :: Char -> [String]
diamond ch = let downHalf = down ch
in (reverse (tail downHalf)) ++ downHalf
LAB 7:
{-
Funcții auxiliare: conversie Char-Word
-}
{-
1. (1p)
Construiți funcția myCycle, care ia ca argument o listă și întoarce lista
repetată la infinit. Ex: myCycle [1,2,3] = [1,2,3,1,2,3,1,2,3,1,2,3,..]
Hint: Puteți defini funcția point-free, folosind funcții din cadrul
modulului Data.List.
http://hackage.haskell.org/package/base-4.6.0.1/docs/Data-List.html
Observaţie: Nu folosiți în implementare funcția cycle. :-)
-}
{-
3. (2p)
Construiți o funcție care întoarce un șir infinit de numere pseudo-aleatoare,
plecând de la o valoare „seed” întreagă.
{-
4. (1p)
Implementați o funcție care convertește un element de tipul Word8 (0 - 255) într-un caracter
alfabetic ('a' - 'z').
{-
5. (1p)
Implementați o funcție care generează o secvență infinită de caractere alfabetice
pseudo-aleatoare, plecând de la o valoare "seed" întreagă.
Observație: Implementați funcția point-free.
Hint: Folosiți funcțiile randoms si wordToAlpha de la exercițiile anterioare.
-}
{-
6. (3p)
Implementați funcția tableToFunc, care primește o listă de asocieri
(caracter-clar, caracter-criptat) și întoarce o funcție de substituție.
Implementați funcția substCrypt, care primește o listă de asocieri
(caracter-clar, caracter-criptat) și un
șir de caractere și întoarce șirul de caractere criptat pe baza tabelei.
Observație: tableToFunc va fi implementată obligatoriu utilizând o clauză
where/let, cu pattern matching.
Observație: substCrypt va fi implementată obligatoriu point-free (nu va
avea parametri expliciți), folosind funcționale și/sau clauze let/where.
-}
rot13Table = [('a','n'),('b','o'),('c','p'),('d','q'),('e','r'),
('f','s'),('g','t'),('h','u'),('i','v'),('j','w'),
('k','x'),('l','y'),('m','z'),('n','a'),('o','b'),
('p','c'),('q','d'),('r','e'),('s','f'),('t','g'),
('u','h'),('v','i'),('w','j'),('x','k'),('y','l'),
('z','m')]
{-
7. (Bonus - 1p)
{- 8. (Bonus - 1p)
Ne propunem să implementăm o funcție de criptare numită encryptVigenere.
Mai multe despre aceasta tehnică de criptare:
http://practicalcryptography.com/ciphers/classical-era/vigenere-gronsfeld-and-autokey/
Fie `xi`, indexul caracterului alfabetic de pe pozitia 'i' din sirul de caractere original.
Fie `yi`, indexul caracterului alfabetic de pe pozitia 'i' din cheia secreta generată la pasul anterior.
Caracterul criptat de pe pozitia 'i' va putea fi obținut alegând cel de-al `xi` caracter
din alfabet, dacă alfabetul ar fi rotit cu `yi` poziții. (vom considera alfabetul indexat de la 0)
Ex:
plaintext: 'def'
secretkey: 'bcd'
{- 9, (Bonus - 2p)
Funcția xorNumbers face xor între două numere întregi.
Exemplu:
xorNumbers 10 3 = 9
Explicație:
Numar -> Reprezentare Binară
10 -> 0 0 0 0 1 0 1 0
3 -> 0 0 0 0 0 0 1 1
--------------------------(xor)
9 -> 0 0 0 0 1 0 0 1
Explicație:
Șir -> Valoare
"zz" -> '0x7a' '0x7a'
"aa" -> '0x61' '0x61'
------------------------------(xor)
"\ESC\ESC" -> '0x1b' '0x1b'
Exemplu:
rollingXor "zb" "aaa" = "\ESC\CAN\ESC"
Explicație:
"zb" se extinde la "zbz" si se face xorStrings între "zbz" si "aaa".
-}
LAB 8:
{-
PP, laboratorul 8: tipuri de date utilizator
-}
{-
1. (2p) Vectori
Se dă tipul de date Vector, reprezentând vectori din spațiul R^3.
Explicații
emptySList :: SList a
emptySList = List []
{-
3. (4p) Arbori binari de căutare
Definiți un tip de date BST a pentru a implementa un arbore binar de
căutare. De asemenea, definiți funcții pentru a insera o valoare într-un
arbore binar de căutare, căutarea unui element într-un arbore binar de
căutare dat, o funcție care întoarce lista elementelor din parcurgerea
în inordine a arborelui și o funcție care întoarce cel mai mic subarbore
care conține două noduri ale căror chei sunt date.
-}
data BST a = UndefinedNode | BSTNode a (BST a) (BST a) | BSTNil deriving Show
{-
4. (BONUS, 2p) Arbore multicăi nevid
Având dat tipul Tree a, definiți funcționala analoagă lui map, care să
aplice o funcție asupra cheilor nodurilor din arbore, și o funcțională
analoagă lui foldl care să parcurgă nodurile în ordinea: rădăcină, copil_1,
copil_2, ... copil_n.
-}
{-
5. (BONUS, 3p) Difference lists
Se cere definirea tipului de date "difference list".
1 : (2 : (3 : xs)) = [1,2,3] ++ xs
emptyDL :: DList a
emptyDL = DL id
LAB 9:
{-
1.(1.5p) Analizați clasa PQueue definită mai jos și scrieți implementările
implicite pentru funcțiile din această clasă:
* fromList
* toList
{-
2.(2.0p) Definiți tipul ListPQ care reprezintă o coadă de priorități ca pe o
listă de elemente. Includeți ListPQ în clasa PQueue.
-}
{-
LeftistPQ reprezintă o coadă de priorități ca pe un arbore binar.
Fiecare nod va conține elementele:
* Prioritatea
* Rank-ul
* Subarborele stang
* Subarborele drept
Referință - pentru mai multe detalii despre construcție: http://typeocaml.com/2015/03/12/heap-
leftist-tree/
Vizualizare: https://www.cs.usfca.edu/~galles/visualization/LeftistHeap.html
-}
{-
3.(2.5p) Definiți operația de "merge" care primește 2 parametri de tipul LeftistPQ și intoarce
un nou LeftistPQ obținut prin combinare.
Cazuri de tratat:
* Dacă unul dintre noduri este Empty
* Dacă ambele noduri sunt Empty
* Dacă nodurile nu sunt Empty
Trebuie definită și operația inorder pentru parcurgerea arborelui - este folosit la validare
-}
{-
4.(1.5p) Includeți LeftistPQ în PQueue
-}
empty = Empty 0
top pq
| isEmpty pq = Nothing
| otherwise = Just $ nodeVal pq
Reminder:
:t foldr
foldr :: (a -> b -> b) -> b -> [a] -> b
Clasa Foldable caracterizează tipurile care pot fi "reduse" la o anumită valoare utilizând
operații specifice (foldr, foldl).
Foldable t este o constrângere de tip, iar "t a" este un container care conține valori de tipul a.
{-
8.(BONUS 1.0p) Adăugați tipurile ListPQ și LeftistPQ în clasa MyFunctor
Funcția f primește ca parametru o valoare din coadă (al doilea element din tuplu)
-}
{-
9.(BONUS 2.0p) Adăugați LeftistPQ în clasa Show
Va trebui ca arborele să fie afișat în modul următor:
"--" x nivel în arbore {valoare din nod}
Dacă nodul este Empty atunci se va afișa în loc de {valoare din nod} "empty"
Ex: Node _ (3,4) {Node _ (4,5) Empty Empty} {Node _ (5,6) {Node _ (6,7) Empty Empty}
Empty} -- nu ne interesează rankul
--(3,4)
----(4,5)
------empty
------empty
----(5,6)
------(6,7)
--------empty
--------empty
------empty <-- și aici este newline la final
LAB 10:
% ?- X = Y.
% X = Y.
% ?- X == Y.
% false.
% ?- X == 1 + 2.
% false.
% ?- X is 1 + 2.
% X = 3.
% ?- X =:= 1 + 2.
% ERROR: =:=/2: Arguments are not sufficiently instantiated
%% LABORATOR 10
%% Prolog – Intro
:- discontiguous exercitiul/2.
%% -----------------------------------------------------------------------------
exercitiul(1, [1, punct]).
%% myConcat/3
%% myConcat(?List1, ?List2, ?List)
%% 'List' este lista formată prin concatenarea listelor 'List1' și 'List2'.
myConcat([], L, L).
myConcat([Head | Tail], L, [Head | R]) :- myConcat(Tail, L, R).
%% -----------------------------------------------------------------------------
exercitiul(2, [0.5, puncte]).
%% myReverse/2
%% myReverse(?List, +RevList)
%% 'RevList' este o listă ce conține elementele listei 'List' în ordine inversă.
%% Regulile pot conține și predicatul myConcat/3.
myReverse([], []).
myReverse([Head | Tail], ResList) :- myReverse(Tail, ResTail),
myConcat(ResTail, [Head], ResList).
%% -----------------------------------------------------------------------------
exercitiul(3, [0.5, puncte]).
%% myReverseAcc/2
%% myReverseAcc(?List, ?Acc, ?RevList)
%% 'RevList' este o listă ce conține elementele listei 'List' în ordine inversă
%% și elementele listei 'Acc'.
%% (Indicație: 'Acc' se va comporta precum un acumulator)
%% Regulile nu trebuie să conține alte predicate (în afară de "cut" și ",").
%% -----------------------------------------------------------------------------
exercitiul(4, [1, punct]).
%% extract/4
%% extract(+List, +Start, +End, -Range)
%% 'Range' reprezintă lista formată din elementele listei 'List' aflate
%% pe pozițiile din intervalul 'Start' .. 'End'. 'Start' va fi întotdeauna
%% mai mic decât 'End'. Primul element se află pe poziția 0. Dacă 'End'
%% depășește lungimea listei, 'Range' va conține toate elementele de la 'Start'
%% la finalul listei.
extract([], _, _, []).
extract([Head | _], 0, 0, [Head]).
extract([Head | Tail], 0, End, [Head | Res]) :- End1 is End - 1,
extract(Tail, 0, End1, Res).
extract([_ | Tail], Start, End, Res) :- Start1 is Start - 1, End1 is End - 1,
extract(Tail, Start1, End1, Res).
%% -----------------------------------------------------------------------------
exercitiul(5, [0.5, puncte]).
%% factorial/2
%% factorial(+N, -Fact)
%% 'Fact' este factorialul lui 'N'.
%% N va fi mereu legat la un număr natural.
factorial(N, 1) :- N < 2, !.
factorial(N, Fact) :- N1 is N - 1, factorial(N1, Fact1), Fact is Fact1 * N.
%% -----------------------------------------------------------------------------
exercitiul(6, [0.5, puncte]).
%% factorial2/2
%% factorial2(?N, ?Fact)
%% 'Fact' este factorialul lui 'N'.
%% Cel puțin unul dintre cele două argumente trebuie să fie legat la un număr.
factorial2(0, 1).
factorial2(N, Fact) :- factorial2(N1, Fact1), N is N1 + 1, Fact is Fact1 * N.
%% -----------------------------------------------------------------------------
exercitiul(7,[1, punct]).
%% palindrom/2
%% palindrom(+List)
%% 'List' este un palindrom.
sublista([], []).
sublista([_ | Tail], SubList) :- sublista(Tail, SubList).
sublista([Head | Tail], [Head | SubList]) :- sublista(Tail, SubList).
%% -----------------------------------------------------------------------------
%% -----------------------------------------------------------------------------
%% Se dau următoarele fapte ce descriu arcele unei păduri de arbori binari.
%% Fiecare nod poate avea maximum doi fii.
%% -----------------------------------------------------------------------------
%% arc/2
%% -----------------------------------------------------------------------------
exercitiul(9, [0.5, puncte]).
%% isLeaf/1
%% isLeaf(?Nod)
%% -----------------------------------------------------------------------------
exercitiul(10, [0.5, puncte]).
%% isRoot/1
%% -----------------------------------------------------------------------------
exercitiul(11, [1, punct]).
%% descendantOf/2
%% descendantOf(?X,?Y)
%% Nodul X este un urmaș a lui Y.
%% -----------------------------------------------------------------------------
exercitiul(12, [2, puncte]).
%% descendants/2
%% descendants(?Nod, ?N)
%% Nodul Nod are N urmași.
descendants(Node, 0) :- isLeaf(Node).
descendants(Node, N) :- arc(Node, Node1), \+ (arc(Node, Node2), Node1 \= Node2),
descendants(Node1, N1), N is N1 + 1.
descendants(Node, N) :- arc(Node, Node1), arc(Node, Node2), Node1 \= Node2,
descendants(Node1, N1), descendants(Node2, N2),
N is N1 + N2 + 2.
%%================
%%=====BONUS======
%%================
%% -----------------------------------------------------------------------------
exercitiul(13, [1, punct, bonus]).
%% sameTree/2
%% sameTree(+Nod, +Nod).
sameTree(N, N).
sameTree(N1, N2) :- descendantOf(N1, N2); descendantOf(N2, N1).
sameTree(N1, N2) :- arc(N3, N1), arc(N4, N2), sameTree(N3, N4).
%% -----------------------------------------------------------------------------
exercitiul(14, [2, puncte, bonus]).
%% drum/3
%% drum(?Nod, ?Nod, ?Lista)
%% exemplu: drum(e, b, [e, c, a, b])
drum(N, N, [N]) :- !.
drum(N1, N2, myReverse(C1)) :- descendantOf(N1, N2), drum(N2, N1, C1), !.
drum(N1, N2, [N1 | P]) :- descendantOf(N2, N1), arc(N1, N3),
(descendantOf(N2, N3); N3 == N2), drum(N3, N2, P), !.
drum(N1, N2, [N1 | P]) :- arc(N3, N1), drum(N3, N2, P).
%% -----------------------------------------------------------------------------
exercitiul(15, [2, puncte, bonus]).
%% cost/3
%% cost(+Nod, +Nod, -Cost).
%% un arc in sus costa -1, unul in jos, 1.
cost(N, N, 0) :- !.
cost(N1, N2, C) :- descendantOf(N1, N2), cost(N2, N1, C1), C is C1 * -1, !.
cost(N1, N2, C) :- descendantOf(N2, N1), arc(N1, N3), (descendantOf(N2, N3); N3 == N2),
cost(N3, N2, C1), C is C1 + 1, !.
cost(N1, N2, C) :- arc(N3, N1), cost(N3, N2, C1), C is C1 – 1.
%% ----------------------------------------
%% ----------------------------------------
%% template/1
%% template(?List)
%% List are forma unei soluții pentru problema pătratului latin.
%% Lungimea soluției este cunoscută și fixă.
template([1/1/_, 1/2/_, 1/3/_, 2/1/_, 2/2/_, 2/3/_, 3/1/_, 3/2/_, 3/3/_]).
%% correct/1
%% correct(?Solution)
%% Solution reprezintă o soluție validă pentru problemă.
correct([]):-!.
correct([X/Y/S | Others]):-
correct(Others),
member(S, [a, b, c]),
once(safe(X/Y/S, Others)).
%% Scrieți predicatul safe/2 utilizat în rezolvarea problemei.
%% Predicatul verifică dacă plasarea simbolului S pe coloana X
%% și linia Y este validă în raport cu lista Others. Aceasta
%% are forma [X1/Y1/S1, X2/Y2/S2 ...].
%% TODO
%% safe/2
%% safe(+X/Y/S, +Others)
safe(_, []) :- !.
safe(X/Y/S, [A/B/C | Others]) :- (S \== C; (S == C, X \== A, Y \== B)),
safe(X/Y/S, Others).
%% -------------------------------------------------------------
%% -------------------------------------------------------------
opus(est, vest).
opus(vest, est).
safeTaran([]).
safeTaran([_]).
safeTaran(Cine) :- sort(Cine, [lup, varza]).
%% vizualizați soluțiile cu
% solve(taran, Sol), validSol(taran, Sol).
% subSet(+Smaller, +Bigger)
% Verifică dacă setul Smaller este inclus în sau egal cu setul Bigger.
subSet(A, B) :- forall(member(X, A), member(X, B)).
% TODO
% boat/2
% boat(-NM, -NC)
% Posibilele combinații de număr de misionari și canibali care pot
% călători cu barca.
%boat(NM, NC) :- bagof(NM, (integer(NM), NM =< 2, NM >= 0), _),
% bagof(NC, ((integer(NC), NC =< NM ; NM =:= 0), NC + NM < 3, NC + NM > 0), _).
%boat(NM, NC) :- bagof(NM/NC, (integer(NM), integer(NC), (NC =< NM ; NM =:= 0), NC + NM
< 3, NC + NM > 0), _).
boat(1, 0).
boat(1, 1).
boat(2, 0).
boat(0, 1).
boat(0, 2).
% TODO
% safe/2
% safe(+NM, +NC)
% Verifică dacă numărul dat de misionari și canibali pot fi pe același
% mal.
% Atenție la de câte ori este adevărat safeMisionari pentru diverse
% valori ale argumentelor - poate influența numărul soluțiilor pentru
% problemă.
safeMisionari(NM, NC) :- once(NM >= NC ; NM == 0).
% TODO
% parseState/3
% parseState(+State, -Mal, -NM_Est, -NC_Est, -NM_Vest, -NC_Vest)
% Întoarce în ultimele 5 argumente malul unde este barca și numerele de
% misionari / canibali de pe malul estic, respectiv vestic, în starea
% dată.
parseState(state(M, NME, NCE, NMV, NCV), M, NME, NCE, NMV, NCV).
% TODO
% initial_state(misionari, -State)
% Determină starea inițială pentru problema misionarilor, în formatul
% ales.
initial_state(misionari, state(est, 3, 3, 0, 0)).
% TODO
% final_state(misionari, +State)
% Verifică dacă starea dată este stare finală pentru problema
% misionarilor.
final_state(misionari, state(vest, 0, 0, 3, 3)).
% TODO
% next_state(misionari, +S1, -S2)
% Produce o stare următoare S2 a stării curente S1.
% Toate soluțiile predicatului next_state pentru o stare S1 dată trebuie
% să fie toate posibilele stări următoare S2 în care se poate ajunge din
% S1.
next_state(misionari, Init, Next):- parseState(Init, M, NME1, NCE1, NMV1, NCV1),
M == est, boat(NM, NC),
NM =< NME1, NC =< NCE1,
NME2 is NME1 - NM, NCE2 is NCE1 - NC,
NMV2 is NMV1 + NM, NCV2 is NCV1 + NC,
safeMisionari(NME2, NCE2),
safeMisionari(NMV2, NCV2),
Next = state(vest, NME2, NCE2, NMV2, NCV2).
%% -------------------------------------------------------------
%% -------------------------------------------------------------
exercitiul(3, [2, puncte]).
% TODO
% preorder/2
% preorder(+N, -Parc)
% Întoarce în Parc o listă de noduri rezultate din parcurgerea în
% preordine începând din noudl N.
preorder(N, [N | PChld]) :- arc(N, Chld), chldDfs(Chld, [], PChld).
preorder(N, [N]) :- \+ arc(N, _).
% nodes(-NN)
% Întoarce în NN toate nodurile din pădurea de arbori.
nodes(NN) :- findall(N, nod(N), NN).
% TODO
% trees/1
% trees(-Trees)
% Întoarce în trees o listă în care fiecare element este parcurgerea
% unui arbore.
trees(Trees) :- nodes(NN), sort(NN, Nodes), traverse(Nodes, [], Trees).
% traverse/3
% traverse(+Nodes, +Vis, -Trees)
traverse(NN, NN, Trees) :- Trees = [].
traverse(NN, Vis, Trees) :- nod(X), \+ member(X, Vis),
preorder(X, Tree),
append(Vis, Tree, NewVis),
sort(NewVis, SNewVis),
traverse(NN, SNewVis, NewTrees),
Trees = [Tree | NewTrees].
exercitiul(5, [3, puncte]).
% TODO
% span/1
% span(-Trees)
% Întoarce o listă de arbori.
% Fiecare arbore este reprezentat prin nodul său rădăcină.
% Fiecare nod este reprezentat ca o listă care în primul element are
% valoarea nodului iar restul elementelor sunt reprezentările nodurilor
% sale copii.
% E.g. Arborele cu a rădăcină, având pe b și c copii, iar b având un
% copil d, este reprezentat ca [a, [b, [d]], [c]].
span(Trees) :- findall(N, (graph(NN), member(N, NN), edges(N, _)), NN),
dfs(NN, [], Trees).
dfs([], _, []).
dfs(N, Vis, [N]) :- graph(NN), member(N, NN), (member(N, Vis), !; \+ edges(N, _)).
dfs(N, Vis, [N | Path]) :- graph(NN), member(N, NN), edges(N, L),
dfs(L, [N | Vis], Path).
dfs([N | NN], Vis, Path) :- member(N, Vis), dfs(NN, Vis, Path).
dfs([N | NN], Vis, Path) :- dfs(N, Vis, Path1), append(Vis, Path1, Vis1),
flatten(Vis1, Vis1FLat),
dfs(NN, Vis1FLat, Path2),
Path = [Path1 | Path2].
LAB 12:
:- discontiguous exercitiul/2.
% ----------------------------------------------------------------------------
% Mașini
conduce(aurel, ford).
conduce(bogdan, bmw).
conduce(cosmin, bmw).
conduce(daniel, ford).
conduce(eugen, bmw).
conduce(florin, dacia).
conduce(george, fiat).
conduce(horia, audi).
conduce(irina, dacia).
conduce(jean, fiat).
conduce(kiki, audi).
conduce(laura, seat).
conduce(marian, mercedes).
conduce(nicodim, opel).
conduce(ovidiu, honda).
conduce(paul, honda).
% Arme
inarmat(aurel, sabie).
inarmat(bogdan, pistol).
inarmat(cosmin, arbaleta).
inarmat(daniel, grenada).
inarmat(eugen, grenada).
inarmat(florin, sabie).
inarmat(george, pistol).
inarmat(horia, arbaleta).
inarmat(irina, pusca).
inarmat(jean, cutit).
inarmat(kiki, prastie).
inarmat(laura, pusca).
inarmat(marian, cutit).
inarmat(nicodim, prastie).
inarmat(ovidiu, maceta).
inarmat(paul, sabie).
% ----------------------------------------------------------------------------
% 1. (1p) Scrieți un predicat suspect(Nume:Marca:Arma) care să fie
% adevărat pentru fiecare suspect al problemei noastre.
exercitiul(1, [1, puncte]).
% ----------------------------------------------------------------------------
% 2. (1p) Scrieți un predicat au_pusca(-ListaNume) care să fie
% adevărat atunci când ListaNume este lista cu numele tuturor celor care
% au pușcă.
exercitiul(2, [1, puncte]).
% ----------------------------------------------------------------------------
% 3. (1p) Scrieți predicatele au_arma(+Arma, -ListaNume)
% și au_marca(+Arma, -ListaNume), care să fie adevărate atunci când
% ListaNume este lista cu numele tuturor celor care au arma de tipul
% Arma, respectiv mașina de tipul Marca.
exercitiul(3, [1, puncte]).
% ----------------------------------------------------------------------------
% 4. (1.5p) Scrieți un predicat arme_bmw(ListaArme) care să fie adevărat
% atunci când ListaArme reprezintă mulțimea tuturor armelor deținute
% de conducători de bmw.
exercitiul(4, [1.5, puncte]).
% ----------------------------------------------------------------------------
% 5. (1.5p) Scrieți un predicat arme_marca(Marca, ListaArme) care să
% fie adevărat atunci când ListaArme reprezintă mulțimea tuturor
% armelor deținute de conducători de mașini de tipul Marca.
exercitiul(5, [1.5, puncte]).
% ----------------------------------------------------------------------------
% 6. (2p) Scrie un predicat marci_arma_unica(ListaMarci) care să afișeze
% lista mașinilor pentru care lista armelor pe care le dețin
% conducătorii unei mărci conține un singur element. Hint: folosiți-vă
% de rezolvarea exercițiului 5. Nu folosiți length/2.
exercitiul(6, [2, puncte]).
marci_arma_unica(ListaMarci) :- findall(Marca, (conduce(_, Marca), arme_marca(Marca, [_])),
ListaMarci).
% ----------------------------------------------------------------------------
% ----------------------------------------------------------------------------
% ----------------------------------------------------------------------------
% 7. (2.5p) Scrie un predicat suspect1/1 care este adevărat doar pentru
% numele suspecților care respectă condiția impusă de replica
% Detectivului A: niciuna dintre armele asociate cu mașina suspectului
% nu indică în mod unic un anumit individ.
exercitiul(7, [2.5, puncte]).
% ----------------------------------------------------------------------------
% A doua replică:
%
% Detectivul A: Nici eu nu știu!
%
% 8. (1.5p) Scrie un predicat suspect2/1 care este adevărat doar pentru
% numele suspecților care respectă condiția impusă de replica
% Detectivului A: marca nu indică unic un individ.
%
% Atenție: informația ce trebuie filtrată acum este cea care
% corespunde primei replici.
exercitiul(8, [1.5, puncte]).
suspect2(Nume:Marca:Arma) :- suspect1(Nume:Marca:Arma),
findall(Name, suspect1(Name:Marca:_), [_, _ |_]).
% ----------------------------------------------------------------------------
% A treia replică:
%
% Detectivul B: Nici eu nu știu!
%
% 9. (1p) Scrie un predicat suspect3/1 care este adevărat doar pentru
% numele suspecților care respectă condiția impusă de replica
% Detectivului B: arma nu identifică unic un individ.
%
% Atenție: informația ce trebuie filtrată acum este cea care
% corespunde primelor două replici.
exercitiul(9, [1, puncte]).
suspect3(Nume:Marca:Arma) :- suspect2(Nume:Marca:Arma),
findall(Name, suspect2(Name:_:Arma), [_, _ |_]).
% ----------------------------------------------------------------------------
% A patra replică:
%
% Detectivul A: Eu tot nu știu!
%
% 10. (1p) Scrie un predicat suspect4/1 care este adevărat doar pentru
% numele suspecților care respectă condiția impusă de replica
% Detectivului A.
%
% Atenție: informația ce trebuie filtrată acum este cea care
% corespunde primelor trei replici.
exercitiul(10, [1, puncte]).
suspect4(Nume:Marca:Arma) :- suspect3(Nume:Marca:Arma),
findall(Name, suspect3(Name:Marca:_), [_, _ | _]).
% ----------------------------------------------------------------------------
% A cincea replică:
%
% Detectivul B: Eu am aflat!
%
% 11. (0.5p) Scrie un predicat suspect5/1 care este adevărat doar pentru
% numele suspecților care respectă condiția impusă de replica
% Detectivului B.
%
% Atenție: informația ce trebuie filtrată acum este cea care
% corespunde primelor patru replici.
exercitiul(11, [0.5, puncte]).
suspect5(Nume:Marca:Arma) :- suspect4(Nume:Marca:Arma),
findall(Name, suspect4(Name:_:Arma), [_]).
% ----------------------------------------------------------------------------
% A șasea replică:
%
% Detectivul A: Și eu am aflat!
%
% 12. (0.5p) Scrie un predicat suspect6/1 care este adevărat doar pentru
% numele suspecților care respectă condiția impusă de replica
% Detectivului A.
%
% Atenție: informația ce trebuie filtrată acum este cea care
% corespunde primelor cinci replici.
exercitiul(12, [0.5, puncte]).
suspect6(Nume:Marca:Arma) :- suspect5(Nume:Marca:Arma),
findall(Name, suspect5(Name:Marca:_), [_]).
COD DISCUTAT LA CURS:
RACKET:
; apel uncurry
(+ 2 3) ; aplicare uncurry
; apel curry
((curry+ 1) 2) ; aplicare funcție în formă curry
; filter
(display '============filter)(newline)
; map
(display '============map)(newline)
(map (λ (x) (+ x 1)) '(1 2 3 4 5)) ; incrementarea unei liste, cu funcție anonimă
(map (curry+ 1) '(1 2 3 4 5)) ; incrementarea unei liste, cu funcție curry aplicată parțial
(map + '(1 2 3 4 5) '(6 7 8 9 10) '(20 30 40 50 60)) ; adunarea a mai multe liste
(display '============curry-member)(newline)
(define flip (λ (f) (λ (a) (λ (b) ((f b) a))))) ; produce o funcție curry identică cu f dar cu argumentele
inversate
; apply
(display '============apply)(newline)
; foldl / foldr
(display '============fold)(newline)
; ======================
; older
(map apply (map curry+ '(1 2 3 4 5)) (map list '(6 7 8 9 10))) ; adunarea a două liste, în două faze
(define flipCurryMember (λ (L) (λ (e) (member e L))))
(define (intersectie M1 M2)
(filter (flipCurryMember M2) M1))
PROMISIUNI:
#lang racket
(define-namespace-anchor a)
(define ns (namespace-anchor->namespace a))
;; clasic
(define prod1
(λ (x y)
(displayln "prod")
(if x (* y (+ y 1)) 0)))
(define test1
(λ (x)
(let ((y 5))
(prod1 x (and (display "y ") y)))))
;; quote + eval
(define prod2
(λ (x y)
(displayln "prod")
(if x (* (eval y ns) (+ (eval y ns) 1)) 0)))
; eval necesită un spațiu de nume în care să evalueze expresia
; aici, am dat spațiul de nume global; o soluție ar fi să transmitem și spațiul de nume ca argument
(define test2
(λ (x)
(let ((y 5))
(prod2 x (quote (and (display "y ") y))))))
;; inchidere λ
(define prod3
(λ (x y)
(displayln "prod")
(if x (* (y) (+ (y) 1)) 0)))
(define test3
(λ (x)
(let ((y 5))
(prod3 x (λ () (and (display "y ") y))))))
;; promisiuni
(define prod4
(λ (x y)
(displayln "prod")
(if x (* (force y) (+ (force y) 1)) 0)))
(define test4
(λ (x)
(let ((y 5))
(prod4 x (delay (begin (display "y ") y))))))
(define y 2)
(delay (and (display "y ") y)) ; -> prim rang
FLUXURI:
#lang racket
; Mihnea Muraru & Andrei Olaru
(define unpack
;(λ (package) (package))) ; închideri
force) ; promisiuni
; =====================================
(define-syntax-rule (stream-cons h t)
;; define-syntax-rule definește o construcție nestrictă,
;; deci apelul stream-cons nu va evalua h și t
(cons h (pack t)))
(define (stream-cdr s)
(unpack (cdr s)))
(define (stream-take s n)
(cond ((zero? n) '())
((stream-null? s) '())
(else (cons (stream-car s) (stream-take (stream-cdr s) (- n 1))))))
(define (stream-drop s n)
(cond ((zero? n) s)
((stream-null? s) s)
(else (stream-drop (stream-cdr s) (- n 1)))))
(define (stream-map f s)
(if (stream-null? s) s
(stream-cons (f (stream-car s))
(stream-map f (stream-cdr s)))))
(define (stream-filter f? s)
(cond ((stream-null? s) s)
((f? (stream-car s)) (stream-cons (stream-car s) (stream-filter f? (stream-cdr s))))
(else (stream-filter f? (stream-cdr s)))))
(define (stream-assoc k s)
(cond
((stream-null? s) #f)
((equal? (car (stream-car s)) k) (stream-car s))
(else (stream-assoc k (stream-cdr s)))))
(define (list->stream L)
(if (null? L) stream-nil
(stream-cons (car L) (list->stream (cdr L)))))
; ===============================================
(display "----- Definiri de fluxuri -----\n")
(display "ones:\n")
;(define ones (letrec ((ones (cons 1 ones))) ones)) ; eroare
;(define (ones) (cons 1 (ones))) ;ciclu infinit
;(define ones (cons 1 (λ () ones))) ; inchideri
;(define ones (cons 1 (delay ones))) ; promisiuni
(define ones (stream-cons 1 ones))
; ATENȚIE: există și în racket definit stream-cons & co. Aici le-am suprascris.
; stream-cons din Racket întoarce un obiect de tip #<stream>
(car ones)
(cdr ones)
(equal? ones (stream-cdr ones))
; cu funcție recursivă
(define (naturalsFrom start)
(stream-cons start
(naturalsFrom (+ start 1))))
(define naturals (naturalsFrom 0))
(define naturals3
(stream-cons 0 (stream-zip-with + ones naturals3)))
(display "naturals:\n")
(stream-take naturals 10)
(stream-take naturals2 10)
(stream-take naturals3 10)
; folosiți această definiție pentru a observa cum se construiesc elementele fluxului
(define naturalsBuild
(let build ((start 0)) ; observați evaluarea când folosim promisiuni pentru întârziere
(stream-cons
start
(build
(and (display `(build ,(+ start 1))) (+ start 1))))))
(define powers-of-2
;; definiție recursivă (explicită)
(letrec ((build (λ (start)
(stream-cons start
(build (* start 2))))))
(build 1)))
(define p-o-2
;; variantă de definire implicită
(stream-cons 1 (stream-map ((curry *) 2) p-o-2)))
(define p-o-2B
;; altă variantă de definire implicită
(stream-cons 1 (stream-zip-with + p-o-2 p-o-2)))
(define BFS ;; găsește toate soluțiile (spațiul de căutare trebuie să fie finit)
(λ (init expand goal?)
(let search ((frontier (list init))) ;; stări de explorat
;(display frontiera)
(if (null? frontier) '() ;; am terminat de explorat?
(let* ((node (car frontier)) ; stare curentă
(other-solutions ;; rezultatul căutării recursive
(search (append (cdr frontier) (expand node)))))
;; stările nou descoperite se adaugă la sfârșit
(if (goal? node)
(cons node other-solutions) ;; am găsit o stare scop (o soluție)
other-solutions)
)))
))
(define lazy-BFS ;; produce un flux de soluții, pe baza unui spațiu de căutare potențial infinit
(λ (init expand goal?)
(let search ((frontier (list init))) ;; stări de explorat
;(display frontiera)
(if (null? frontier) stream-nil ;; am terminat de explorat?
(let ((node (car frontier))) ;; stare curentă
(if (goal? node)
;; dacă nod nu este scop, continuăm căutarea pentru a putea livra un nod scop
(search (append (cdr frontier) (expand node)))
)))
)))
(define all-palindromes
(lazy-BFS '()
expand-string
palindrome?
))
(displayln "palindroamele de la 50 la 60:")
(stream-take (stream-drop all-palindromes 50) 10)
(define levels-stream
(stream-cons '(()) ; primul nivel conține doar șirul gol
(stream-map (compose
((curry apply) append) ; facem flatten după ce
((curry map) expand-string)) ; am expandat întreg nivelul
levels-stream))) ; și formăm un nou nivel
;(stream-take levels-stream 3)
(define search-space ; forma flat pentru niveluri
(let build ((cLevel '()) (levels levels-stream))
(if (null? cLevel) (build (stream-car levels) (stream-cdr levels))
(stream-cons (car cLevel) (build (cdr cLevel) levels)))))
;(stream-take search-space 20)
TIPURI IN HASKELL:
module C7 where
{- rulați
addNat (Succ (Succ doi)) (Succ (Succ (Succ Zero)))
addNat unu doi
addNat doi Zero == doi
:t addNat
-}
-- lucrare
--m :: ?
mfl
| l == [] = []
| True = f (head l) + 1 : m f (tail l)
-------------------------------------------------------
{- varianta de la curs:
treeB = Node 1 [stL 1, stR 1] where
stL n = Node (2*n) [stL (2*n), stR (2*n)]
stR n = let r=2*n+1 in
Node r [stL r, stR r]
-}
{- încercați la consolă
limit 5 treeOnes
limit 5 treeB
take 10 $ preord treeB -- doar calea de pe partea stângă a arborelui, pentru că nu ne întoarcem
niciodată
preord $ limit 5 treeB
-}
CLASE IN HASKELL:
module PP08 where
import Debug.Trace
-- Pair 1 2
-- List [1,2,3]
l = List [Atom 1, Atom 2, List [Atom 3, Atom 4], Atom 5]
data Pair a = P a a
data NestedList a = Atom a
| List [NestedList a]
deriving Show
fromAtom (Atom x) = x
fromAtom _ = undefined
fromList (List l) = l
fromList _ = undefined
{-- v1
class Container a where contents :: a -> [a]
instance Container [x] where
-- contents [x] = [x]
contents = id
--}
{-- v2
class Container a where contents :: a -> [b]
--{--
f1 x y z = if x == y then x else z
f2 x y = if (invert x) == (invert y)
then contents x
else contents y
f3 x y = (invert x) ++ (invert y)
f4 x y z = if x == y then z else
if x > y then x else y
--}
----------------------------
data Tree a = Nil -- arbore vid
| Leaf a -- frunză
| Node a [Tree a] -- nod cu un număr oarecare de copii
-----------------------
graph = G [(3, 8), (3, 10), (3, 5), (5, 11), (7, 8), (7, 11),
(8, 8), (8, 9), (11, 2), (11, 5), (11, 9), (11, 10)]
{-
nodes (G (e:g)) = [fst e, snd e] ++
filter (\n -> not (elem n [fst e, snd e])) (nodes (G g))
-}
nodes (G []) = []
nodes (G (e:g)) = let eNodes = [fst e, snd e] in
eNodes ++
filter (not . (flip elem $ eNodes)) (nodes $ G g)
outgoing v (G edges) = map snd $ filter (\(a, b) -> a == v) edges
-- toTree implementat doar pentru grafuri care pot fi parcurse integral pornind din primul nod din
prima muchie.
instance TreeLike Graph where
makeOne v = G [(v, undefined)]
toTree g@(G edges) = dfsFrom (head $ nodes g) [] where
dfsFrom v visited
| elem v visited = --trace ("Visiting " ++ show v ++ " seen " ++ show visited)
$
Nil
| otherwise = --trace ("Visiting " ++ show v ++ " seen " ++ show visited) $
case outgoing v $ G edges of
[] -> Leaf v
children -> Node v subTrees where
subTrees = foldl f [] children
f previousTrees child =
dfsFrom child (v : visited ++ concatMap preord
previousTrees)
: previousTrees
-- verificare makeOne
{-
makeOne 5 -- nu știm ce tip trebuie să întoarcă makeOne (este ambiguu)
fromAtom $ makeOne 5
preord $ makeOne 5
nodes $ makeOne 5 -- excepție (undefined), după ce a afișat totuși primul nod
head $ nodes $ makeOne 5 -- nu dă excepție mulțumită evaluării leneșe
-}
module C9 where
import Data.Char (isDigit)
import Debug.Trace
import PP08
-- o expresie aritmetică este fie un număr, fie o operație între alte 2 expresii
data Expr a = Number a | Op (Expr a) a (Expr a) deriving (Show, Eq)
-- ne dorim un parser care Parser Char (Expr String) care să parseze expresii numerice din șiruri de
caractere
--- construiește un parser care parsează un element din input, dacă acesta respectă funcția dată
makeTokenParserF :: (i -> Bool) -> Parser i i
--makeTokenParserF f = \(h:t) -> if f h then (Parsed h, t] else (Failed, (h:t)) --sau:
makeTokenParserF _ [] = (Failed, [])
makeTokenParserF f input@(h:t) = if f h then (Parsed h, t) else (Failed, input)
{-- vedeți cum se poate folosi iterate împreună cu parserul pentru cifre
take 10 $ iterate (digitParser . snd) $ digitParser "2345"
take 20 $ map fst $ iterate (digitParser . snd) $ digitParser $ concatMap show [1..]
-}
--- produce un nou parser, care avansează în input atâta timp cât poate aplica perserul dat
--- rezultatele parsărilor individuale sunt adunate într-o listă
--- la sfârșit, asamblează lista folosind funcția process
(>*>) :: Eq b => Parser a b -> ([b] -> c) -> Parser a c
(>*>) parser process =
(\results ->
--- aplicăm process peste lista rezultatelor, închidem în Parsed,
(Parsed $ process $ map (res . fst) $ results,
--- și lăsăm ca neprelucrat ce a rămas de la ultima parsare
snd $ last results)) .
{-
:t (>*>) digitParser
-- folosim read pentru a citi numărul dintr-un șir de caractere care conține un număr
-- folosim fromInteger pentru a indica lui read că trebuie să citim un întreg
digitParser >*> (fromInteger . read) $ "2345+6"
-}
--- produce un nou parser care este concatenarea (compunerea) a două parsere cu rezultate de
același tip
--- ce rămâne de parsat de la primul parser va fi dat spre parsare celui de-al doilea parser
--- rezultatele parsării de la cele două parsere vor fi fuzionate într-o pereche
(>.>) :: Parser i rA -> Parser i rB -> Parser i (rA, rB)
(>.>) p1 p2 = (\(res1, rem1) -> case res1 of -- ne uităm la rezultatul parsării cu p1
Failed -> (Failed, rem1) -- dacă p1 a eșuat, eșuează
Parsed r1 ->
case p2 rem1 of -- altfel parsăm ce rămâne după parsarea cu p1
(Parsed r2, rem2) -> -- și, dacă reușește, punem rezultatele într-
o pereche
(Parsed (r1, r2), rem2)
(Failed, _) -> (Failed, rem1) -- dacă p2 a eșuat, eșuează
) . p1
{-- vedeți ce efect are concatenarea parserelor:
:t digitParser >.> digitParser
digitParser >.> digitParser $ "2345"
digitParser >.> digitParser >.> digitParser $ "2345"
digitParser >.> operatorParser $ "2+5"
numberParser >.> operatorParser >.> numberParser $ "22+55"
-}
--- produce un nou parser unde rezultatul vine din procesarea rezultatului parserului dat
(>=>) :: Parser a b -> (b -> c) -> Parser a c
(>=>) parser process = (\(res, rem) -> case res of --- dacă parsarea s-a realizat cu succes,
Parsed r -> (Parsed $ process r, rem) --- procesăm
rezultatul acesteia;
otherwise -> (Failed, rem) --- altfel, eșec
) . parser
--- parsează un operand, care este un număr sau o expresie între paranteze;
--- rezultatul parsării este o expresie
operandParser =
--- este paranteză deschisă, urmată de expresie, urmată de paranteză închisă
--- rezultatul parsării va fi (('(', expr), ')'), din care ne interesează doar expresia
((tokenParser '(' >.> exprParser >.> tokenParser ')') >=> (\((_, e), _) -> e))
>|>
--- sau este un număr
numberParser
--- parsează o expresie care este un număr sau o operație între doi operanzi
--- rezultatul parsării este o expresie
exprParser = (
--- este operand, operator, operand
--- rezultatul parsării este de exemplu ((expr, '+'), expr), din care producem
--- o unică expresie
(operandParser >.> operatorParser >.> operandParser)
>=> (\((e1, op), e2)-> Op e1 [op] e2 ))
>|>
--- sau este un număr
numberParser
{-
exprParser $ "123+((25+3)*5)"
res . fst . exprParser $ "123+((25+3)*5)"
-}
-- să calculăm!
{--
computeExpr $ "123+((25+3)*5)"
-}
PROLOG – DIVERSE:
% Progress →
% valori de prim rang în Prolog -- predicate/valori booleene vs argumente/diverse
tipuri/liste/structuri
% ideea de relație între concepte
% exemplu cu Alice: ce concepte sunt? (lion, unicorn, days), ce relații sunt (yesterday, lies,
saysLies)
% Manual Prolog
% http://www.swi-prolog.org/pldoc/doc_for?object=manual
% http://www.swi-prolog.org/pldoc/man?section=builtin
q(X, X) :- p(X).
yesterday(mon, sun).
yesterday(tue, mon).
yesterday(wed, tue).
yesterday(thu, wed).
yesterday(fri, thu).
yesterday(sat, fri).
yesterday(sun, sat).
saysItLiedYesterday(Animal, Today) :-
yesterday(Today, Yesterday),
lies(Animal, DaysLies),
member(Today, DaysLies),
\+ member(Yesterday, DaysLies).
% solutia
sol(Today) :- saysItLiedYesterday(lion, Today), saysItLiedYesterday(unicorn, Today).
% 0. o funcție simplă pe liste
% ==========================================
% myMember(+Elem, +Lista)
myMember(_, []) :- fail. % lista vida nu poate contine elementul. Aceasta linie poate sa lipseasca.
% myMember(E, [H|_]) :- E == H.
myMember(E, [E|_]). % elementul este primul element din lista
myMember(E, [H|T]) :- E \= H, myMember(E, T). % elementul nu este primul din lista.
inc(X, Y) :- Y is X + 1.
% doresc ceva echivalent cu map (+1) list
% 2. debugging:
% ==============================================
% 3. variabile neinstanțiate
% ==========================================
% any(X).
any(X) :- display(X).
% sau: any(X) :- format("X este: ~w~n", [X]).
any(X, X).
% încercați:
% ?- any(X, Y).
/* de executat la consolă:
?- any(X,Y), X = 5.
X = Y, Y = 5.
?- any(X,Y), Y = 5.
X = Y, Y = 5.
?- [1,2,3] = [1,2,3].
true.
?- [1,X,Y] = [1,2,3].
X = 2,
Y = 3.
?- [1,X,Y] = [Z,2,3].
X = 2,
Y = 3,
Z = 1.
?- [1,X,Y] = Z.
Z = [1, X, Y].
?- [1,X,Y] = Z, (X,Y)=(2,3).
X = 2,
Y = 3,
Z = [1, 2, 3].
?-
*/
% 4. generarea numerelor
% ==========================================
% puterea generativă a limbajului: generarea unei liste
% la consolă:
%
% ?- member(1, [1,2,3])
% ?- member(X, [1, 2, 3]).
% ?- member(1, L).
% ?- length(L, 3), member(1, L), member(2, L), member(3, L).
/*
?- append([1,2,3], [2,3,4], L).
L = [1, 2, 3, 2, 3, 4].
?- append([1,2,3], L, [1,2,3,4,5]).
L = [4, 5].
?- 1 < 2.
true.
*/
/*
?- findall(X, (member(X, [1,2,3,4,5]), X > 2), Bag).
Bag = [3, 4, 5].
?-
*/
% 5. cut și fail
% ==============================================
min(X, Y, M) :- X =< Y, M is X.
min(X, Y, M) :- X > Y, M is Y.
min2(X, Y, M) :- X =< Y, M = X.
min2(X, Y, M) :- X > Y, M = Y.
% Echivalent cu min2.
min3(X, Y, X) :- X =< Y.
min3(X, Y, Y) :- X > Y.
este(lili, liliac).
este(fifi, papagal).
zboara(liliac).
zboara(papagal).
% print(_).
prettyPrintList(L) :- ppListH(L, 1).
ppListH([], N) :- format("completed, ~w elements printed.~n", [N]).
ppListH([H|T], I) :- format("element no. ~w: ~w~n", [I, H]), I1 is I + 1,
ppListH(T, I1).
% iterarea peste soluțiile unui scop
% ==========================================
% filter cu findall:
% păstrează din lista Li elementele pentru care predicatul p este
% adevărat
filterP(LI, LO) :-
findall(X, % <- pune acele elemente X
( member(X, LI) % <- care sunt parte din lista LI
, % <- și
p(X) % <- pentru care pe este adevărat
), LO). % <- în lista LO
p(2).
p(4).
path(P) :- initialG(SI),
path(SI, P, [SI]).