content: {-# LANGUAGE ImplicitParams #-}
  
  -- From https://ocharles.org.uk/blog/posts/2014-12-11-implicit-params.html
  
  import Data.Char
  
  
  type LogFunction = String -> IO ()
  
  type Present = String
  
  queueNewChristmasPresents :: LogFunction -> [Present] -> IO ()
  queueNewChristmasPresents logMessage presents = do
    mapM (logMessage . ("Queueing present for delivery: " ++)) presents
    return ()
  
  queueNewChristmasPresents2 :: (?logMessage :: LogFunction) => [Present] -> IO ()
  queueNewChristmasPresents2 presents = do
    mapM (?logMessage . ("Queueing present for delivery: " ++)) presents
    return ()
  
  
  ex1 :: IO ()
  ex1 =
    let ?logMessage = \t -> putStrLn ("[XMAS LOG]: " ++ t)
    in queueNewChristmasPresents2 ["Cuddly Lambda", "Gamma Christmas Pudding"]
  
  
  ex2 :: IO ()
  ex2 = do
    -- Specifies its own logger
    ex1
  
    -- We can locally define a new logging function
    let ?logMessage = \t -> putStrLn (zipWith (\i c -> if even i
                                                       then c
                                                       else toUpper c)
                                             [0..]
                                             t)
    queueNewChristmasPresents2 ["Category Theory Books"]
  
  