{-- HIGHER ORDER FUNCTIONS --}

-- The function twice receive a function and
  its argument and apply two times on it .
twice :: (a->a) -> a -> a
twice f x = f (f x)


prod :: Integer -> Integer -> Integer
prod x y = x * y
g = prod 4 -- partial application! this is a function
  24
  = > 48

-- foldr, foldl as reduce/accumulator
fat :: Integer -> Integer
fat n = foldr (*) 1 [1..n]

-- mapping values using map
s = map (\n -> n + 1) [1..10]
  = > sum +1 for each value of [ 1 .. 10 ]
  = > [ 2,3,4,5,6,7,8,9,10,11 ]


-- zipWith definition
zipWith' :: (a -> b -> c) -> [a] -> [b] -> [c]
zipWith' _ [] _ = []
zipWith' _ _ [] = []
zipWith' f (x:xs) (y:ys) = f x y : zipWith' f xs ys

-- fliping function arguments
flip' :: (a -> b -> c) -> (b -> a -> c)
flip' f = g
  where g x y = f y x


-- filtering
evens1to10 = filter even [1..10]

largestDivisible :: (Integral a) => a
largestDivisible = head (filter p [100000, 99999..])
  where p x = x `mod` 3829 == 0

-- takeWhile get the the values until condition matchs
n = sum $ takeWhile (<10000) $ filter odd $ map (^2) $ [1..]
v = takeWhile (/=' ') "bananas assadas" -- bananas

- HIGHER ORDER FUNCTIONS -
 The function twice receive a function and
 partial application! this is a function
 foldr, foldl as reduce/accumulator
 mapping values using map
 zipWith definition
 fliping function arguments
 filtering
 takeWhile get the the values until condition matchs
 bananas

  its argument and apply two times on it .
twice :: (a->a) -> a -> a
twice f x = f (f x)


prod :: Integer -> Integer -> Integer
prod x y = x * y
  24
  = > 48

fat :: Integer -> Integer
fat n = foldr (*) 1 [1..n]

s = map (\n -> n + 1) [1..10]
  = > sum +1 for each value of [ 1 .. 10 ]
  = > [ 2,3,4,5,6,7,8,9,10,11 ]


zipWith' :: (a -> b -> c) -> [a] -> [b] -> [c]
zipWith' _ [] _ = []
zipWith' _ _ [] = []
zipWith' f (x:xs) (y:ys) = f x y : zipWith' f xs ys

flip' :: (a -> b -> c) -> (b -> a -> c)
flip' f = g
  where g x y = f y x


evens1to10 = filter even [1..10]

largestDivisible :: (Integral a) => a
largestDivisible = head (filter p [100000, 99999..])
  where p x = x `mod` 3829 == 0

n = sum $ takeWhile (<10000) $ filter odd $ map (^2) $ [1..]
