-- defining functions: basic ways
even :: Integer -> Bool
even n = n `mod` 2 == 0
-- even = \ n -> n `mod` 2 == 0
addSq :: Num a => a -> a -> a
addSq x y = x ^ 2 + y ^ 2
-- add = \ x -> \ y -> x ^ 2 + y ^ 2
{-
splitAt :: Int -> [a] -> ([a],[a])
splitAt n as = (take n as, drop n as)
recip :: Fractional a => a -> a
recip x = 1 / x
-}
-- defining functions: if then else vs guards
myAbs :: Int -> Int
{-
myAbs n = if n >= 0 then n else -n
-}
myAbs n | n >= 0 = n
| otherwise = -n
{-
mySignum n = if n < 0 then -1 else
if n == 0 then 0 else 1
-}
mySignum n | n < 0 = -1
| n == 0 = 0
| otherwise = 1
{-
otherwise = true
-}
-- defining functions: case vs pattern matching
myNot :: Bool -> Bool
myNot b = case b of
True -> False
False -> True
{-
myNot True = False
myNot False = True
-}
myLength :: [Int] -> Int
{-
myLength as = case as of
[] -> 0
(_ : as) -> 1 + myLength as
-}
myLength [] = 0
myLength (_ : as) = 1 + myLength as
-- pattern matching is possible even for integers (naturals)
fact :: Integer -> Integer
{-
fact n = if n == 0 then 1 else (n + 1) * fact n
-}
fact 0 = 1
fact (n + 1) = (n + 1) * fact n
-- list comprehensions
{-
sum :: Num a => [a] -> a
sum [] = 0
sum (n : ns) = n + sum ns
-}
yourLength as = sum [1 | _ <- as ]
myConcat ass = [ a | as <- ass, a <- as ]
myFact n = product [1..n]
-- calculating the list of prime numbers
factors n = [ x | x <- [1..n], n `mod` x == 0 ]
prime n = factors n == [1, n]
primes n = [ x | x <- [2..n], prime x]
-- the zip function
myZip :: [a] -> [b] -> [(a,b)]
myZip [] _ = []
myZip _ [] = []
myZip (a : as) (b : bs) = (a, b) : myZip as bs
upFrom n = n : upFrom (n + 1)
-- upFrom n = [n..]
-- tagging list elements with their position numbers
positions :: Eq a => a -> [a] -> [Int]
positions a as = [ i | (i, a') <- zip (upFrom 0) as, a' == a ]
-- pairs of consecutive elements in a list
pairs :: [a] -> [(a,a)]
{-
pairs [] = []
pairs [_] = []
pairs (a : a' : as) = (a, a') : pairs (a' : as)
-}
pairs as = zip as (tail as)
{-
tail (_ : as) = as
-}
-- checking if a list is ordered using pairs
ordered :: Ord a => [a] -> Bool
ordered as = and [ a <= a' | (a, a') <- pairs as ]
{-
and [] = True
and (True : as) = and as
and (False : _) = False
-}
downFrom n = n : downFrom (n - 1)
-- quicksort algorithm
qsort [] = []
qsort (p : as) = qsort smaller ++ [p] ++ qsort bigger
where smaller = [ a | a <- as, a <= p ]
bigger = [ a | a <- as, a > p ]