-- | Module Ex5 where we learn about Writer, tell and logging.
module Ex5
    (mapWithLog,gcdWithLog,filterWithLog,foldrWithLog
    ) where

import Control.Monad.Trans.Writer.Lazy
-- | Obtaining greatest common denominator. implemented with 'Writer'
gcdWithLog :: Int -> Int -> Writer [String] Int
gcdWithLog a b
  | b == 0 = do
      tell ["Finished with " ++ show a]
      return a
  | otherwise = do
      tell [show a ++ " mod " ++ show b ++ " = " ++ show (a `mod` b)]
      gcdWithLog b (a `mod` b)


-- | 'map' with logs.
mapWithLog :: Show a => (a -> b) -> [a] -> Writer [String] [b]
mapWithLog _ [] = do
  tell ["map []"]
  return []
mapWithLog f (x:xs) = do
  tell ["map " ++ show x]
  mapXs <- mapWithLog f xs
  return $ f x : mapXs

-- | Implementation of 'filter' with logging. Easy to implement if you have 'mapWithLog'
filterWithLog :: Show a => (a -> Bool) -> [a] -> Writer [String] [a]
filterWithLog f [] = do
  tell ["end"]
  return []
filterWithLog f (x:xs) =
  if (f x) then
    do
      tell [(show x)++ " accepted"]
      filteredXS <- (filterWithLog  f xs)
      return $ x: filteredXS
  else
    do
      tell [(show x)++ " rejected"]
      filteredXS <- filterWithLog f xs
      return filteredXS


-- | Implementation of 'foldr' with logging.
foldrWithLog :: (Show a, Show b)=> (a->b->b)->b ->[a]  -> Writer [String] b
foldrWithLog f end []=do
  tell ["Last element:  "++ show end]
  return end
foldrWithLog f end (x:xs) = do
  folded <- foldrWithLog f end xs
  let res = f x folded
  tell [(show x) ++"+"++ (show folded)++"="++ show res]
  return res
