import Debug.Trace -- comenzile din comentarii care încep cu -- \> sunt de scris la consolă -- :help (sau :?) -- :set prompt "λ> " -- :r (:reload) pentru reîncărcarea sursei -- :! com -- pentru rularea unei comenzi a sistemului de operare -- (e.g. :! clear / :! cls sau :! ls / :! dir) -- :t add1 -- (:type) -- află tipul oricărei expresii -- :t (+) -- pentru operatori trebuie dați în forma prefixată -- :: înseamnă "are tipul" -- v :: => tip = v are tipul tip, în contextul de tip -- de asemenea: -- :i add1 -- (:info) -- funcționează și pentru operatori, e.g. :i + -- Tipuri de date -- \> :type 1 -- 1 :: Num a => a -- 1 este de un tip oarecare, cu condiția să fie un tip numeric -- \> :t 1.2 -- 1.2 :: Fractional a => a -- 1.2 este de un tip oarecare, cu condiția să fie fracțional -- \> :t True -- True :: Bool -- \> :t False -- False :: Bool -- \> :t [1,2,3] -- [1,2,3] :: Num t => [t] -- este o listă de elemente de tip t, iar t este un tip numeric -- \> :t (1, 'a') -- (1, 'a') :: Num t => (t, Char) -- o pereche -- \> :t (1, 'a', True, [5..9]) -- un tuplu -- (1, 'a', True, [5..9]) :: (Num t1, Num t, Enum t1) => (t, Char, Bool, [t1]) -- perechile și listele NU sunt același lucru -- toate elementele dintr-o listă sunt de același tip -- elementele dintr-un tuplu pot fi de tipuri diferite -- în Haskell avem operatori infixați -- \> [1..] -- o listă infinită -- \> [1..20] -- [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20] -- \> [1,4..20] -- [1,4,7,10,13,16,19] -- \> head [1,2,3] -- 1 -- \> tail [1,2,3] -- [2,3] -- \> (tail [1,2,3]) -- [2,3] -- \> [1,2,3] !! 2 -- 3 -- \> 1 : [2,3,4] -- [1,2,3,4] -- \> 1 + 2 -- 3 -- \> fst (1, 'a') -- 1 -- \> snd (1, 'a') -- 'a' -- șirurile de caractere sunt același lucru (ca tip) cu liste de caractere -- λ> head "abcd" -- 'a' -- λ> tail "abcd" -- "bcd" -- elem este member -- ++ este operatorul de concatenare {- let primes = sieve [2..] where sieve (x:ns) = x : sieve [n | n <- ns, n `mod` x /= 0] \ take 10 primes [2,3,5,7,11,13,17,19,23,29] \ primes !! 1000 -} -- Funcții -- \ stă pentru lambda -- definire directă a funcției add1 :: Num t => t -> t -> t -- necesar pentru că sinteza de tip determină că add1 este pe întregi add1 = \x y -> ((+) x y) -- (add1 1 2) -- ((add1 1) 2) -- add1 1 2 -- \> :t add1 -- aplicare parțială -- \> map (add1 1) [1..5] -- un operator pot să îl folosesc în formă infixată sau prefixată cu paranteze -- o funcție pot să o folosesc în formă prefixată sau infixată cu ` -- λ> 1 `add1` 2 -- în Haskell toate funcțiile sunt funcții curry add2 = \x -> \y -> (((+) x) y) -- cu toate parantezele și în formă curry, dar ne-necesar add3 = \x y -> x + y -- PATTERN MATCHING add4 x y = x + y -- "dacă apelez add4 cu argumentele x și y, valoarea întoarsă este" -- transformare operator -> funcție (formă infixată -> formă prefixată add5 = (+) -- "add5 este același lucru cu funcția (+)" -- transformarea inversă: 1 `add6` 3 -- p-m incomplet (non-exhaustiv) addX 1 2 = 3 addX 1 x = x + 1 addX 5 6 = 11 --addX (x+y) z = x + y + z -- nu pot face p-m decât pe constructori de bază -- în Haskell toți identificatorii încep cu literă MICĂ -- în Haskell CONTEAZĂ INDENTAREA -- Perechi (acces cu fst și snd) -- \> (1, 'a') -- Tupluri -- \> ('a', [1,2,3], False) -- Liste, acces cu head și tail, funcții utile: (:), elem, (!!), (++) -- \> [1, 2, 3] -- \> [1..10] -- \> [1, -1..-20] -- setează pasul listei (rația progresiei aritmetice) -- \> ['a'..'z'] len1 l = if l == [] then 0 else 1 + len1 (tail l) -- pattern-matching len2 [] = 0 len2 (h:t) = 1 + len2 t -- "dacă len2 este aplicat pe o listă care a fost obținută prin aplicarea lui : -- între ceva și altceva, atunci leagă ceva la h și leagă altceva la t și evaluează -- corpul" -- parantezele sunt puse doar pentru asociativitate -- p-m face o legare a variabilelor din pattern în așa fel încât să se potrivească cu valoarea parametrului actual -- când apelez len2 [1,2,3], haskell leagă în așa fel încât [1,2,3] să fie rezultatul expresiei h:t -- "ce ar trebui să fie h și t astfel încât h:t -> [1,2,3] -- patternul arată cum a fost construită valoarea dată ca argument -- și dacă patternul se potrivește, atunci se fac legările onform cu patternul len2b (h1:h2:h3:[]) = 3 -- când voi apela, Haskell întreabă "ce ar putea fi h1 h2 h3 aî (h1:h2:h3:[]) să dea argumentul cu care am apelat?" len2c [] = 0 len2c (h1:h2:h3:t) = 3 + len2c t -- merge doar pentru liste de lungime multiplu de 3 len2d [] = 0 len2d (_ : t) = 1 + len2d t -- nu folosesc partea de pattern dinainte de : -- "_" înseamnă că acolo este o valoare, dar mie în corpul funcției nu îmi trebuie mynull [] = True mynull [x] = undefined mynull (_:_) = False -- mynull aruncă excepție doar pe liste de 1 element -- case len3 l = case l of [] -> 0 otherwise -> 1 + len3 (tail l) len3b l = case l of [] -> 0 _:t -> 1 + len3b t -- utilizare p-m și underscore --inline: len3c l = case l of []->0; _:t->1+len3c t -- gărzi (vedeți https://wiki.haskell.org/Pattern_guard ) len4 l | l == [] = 0 | otherwise = 1 + len4 (tail l) -- gărzile sunt legate de un = -- în gărzi pot pune condiții complete (în case pot pune doar patter-match pe valoarea unei variabile, după care fac case) -- inline: len4b l | l == [] = 0 | length l > 0 = len4b (tail l) + 1 -- let len5 l = let lt = len5 (tail l) in case l of [] -> 0; _:_ -> lt + 1 -- observați legarea leneșă: lt nu dă eroare dacă lista e vidă pentru că nu ajunge să fie folosit -- where len6 l | l == [] = 0 | otherwise = lt + 1 where t = tail l lt = len6 t -- gărzi pe aceeași linie, și where len6b l | l == [] = 0 | otherwise = lt + 1 where t = tail l; lt = len6b t -- let in este o expresie -- where se folosește împreună cu un = sau cu o serie de gărzi -- ... și cu let len7 l | l==[] = 0 | True = let lt = len7 (tail l) in 1 + lt -- Fluxuriones = 1 : ones naturals = 0 : map (+1) naturals evens = zipWith (+) naturals naturals -- take 10 naturals -- take 10 evens -- List comprehensions -- [x+2 | x <- [1..20], x `mod` 3 == 0] -- [ expr | var <- domeniu, var2 <- domeniu2, cond, cond, cond ] evens2 = [x | x <- naturals, mod x 2 == 0] cart a b = [(x,y) | x <- a, y <- b] -- cart "abcd" [1..5] carte a b = [(x,y) | x <- a, x `mod` 2 == 0, y <- b] -- carte [1..15] "abcd" mapLC f l = [ f e | e <- l] filterLC f l = [ e | e <- l, f e] -- mapLC (+5) [1..5] -- filterLC odd [1..10] --map (10 /) [1,2,5,10] --map (/ 10) [1,2,5,10] lista = ["unu", "ceva", "", "argument", "", "altceva", "vid", ""] res = map (\ s -> "["++s++"]") (filter (\ s -> not (null s)) lista) -- paren = "[" ++ s ++ "]" --paren s = (++) "[" ((++) s "]") --paren s = (++) "[" ((flip (++)) "]" s) paren = ("["++) . (flip (++)) "]" res2 = (map paren) (filter (not . null) lista) res3 = (map paren . filter (not . null)) lista tform = map paren . filter (not . null) lista5 = (map . (+)) 5 [1..5] -- lista5 = map . (+) $ 5 [1..5] -- aplică 5 pe [1..5] res4 = (map paren) (filter (not . null) lista) res5 = map paren $ filter (not.null) lista -- TranspusaȘ -- apply map list M -- în Racket aveam apply și map pe mai multe liste transpose m = foldr -- (zipWith (:)) -- variantă point-free (\ row trans -> trace ("asamblez "++(show row)++" in "++(show trans)) $ zipWith (:) row trans) (map (\ c -> []) (head m)) m -- pentru trace trebuie la început: import Debug.Trace -- vedeți construcția tipului aplicând constructorul de tip pentru liste: sumList :: ([] Integer) -> Integer sumList [] = 0 sumList (h:t) = h + sumList t