Module: Control.Monad

Table of Contents

  • Index
  • Repository
  • 1 Control.Monad - Monad Combinators

    This module provides functions to manipulate monads.

    Module Documentation

    1.1 join

    join :: Monad m => m (m a) -> m a 
    join mma = do 
       ma <- mma 
       a  <- ma 
       return a
    
    join mma = 
      mma >>= \ ma -> 
      ma  >>= \ a  ->
        return a
    

    Example:

    > import Control.Monad
    
    > :t join
    join :: Monad m => m (m a) -> m a
    > 
    
    > join $ Just (Just 10)
    Just 10
    > join $ Just Nothing
    Nothing
    > 
    
    
    -- Equals to concat when applied to lists 
    --
    > join  [[1, 2], [3], [4, 5, 6]]
    [1,2,3,4,5,6]
    > 
    
    > concat  [[1, 2], [3], [4, 5, 6]]
    [1,2,3,4,5,6]
    > 
    
    > join (Right (Right "It is right"))
    Right "It is right"
    > 
    >
    > join (Right (Left "It is wrong"))
    Left "It is wrong"
    > 
    > join (Left (Right "It is right"))
    Left (Right "It is right")
    > 
    > join (Left (Left "It is right"))
    Left (Left "It is right")
    > 
    
    > import Control.Monad.Identity 
    
    > Identity 100
    Identity 100
    > 
    
    > join (Identity (Identity 20))
    Identity 20
    >
    

    1.2 liftM

    liftM is equivalent to fmap. Apply a function to monad

    liftM :: Monad m => (a -> b) -> m a -> m b =
    liftM  f ma  = do  
      a <- ma
      return $ f a
    
    > import Control.Monad
    
    > fmap (+1) [1, 2, 3, 4]
    [2,3,4,5]
    > fmap (+1) (Just 10)
    Just 11
    > fmap (+1) Nothing
    Nothing
    > 
    
    > liftM (+1) [1, 2, 3, 4]
    [2,3,4,5]
    > 
    > liftM (+1) (Just 10)
    Just 11
    > 
    > liftM (+1) Nothing
    Nothing
    > 
    
    > liftM lines $ readFile "/etc/lsb-release"
    ["DISTRIB_ID=Ubuntu","DISTRIB_RELEASE=15.04","DISTRIB_CODENAME=vivid","DISTRIB_DESCRIPTION=\"Ubuntu 15.04\""]
    > 
    > liftM length $ liftM lines $ readFile "/etc/lsb-release"
    4
    > 
    
    > liftM (length . lines ) $ readFile "/etc/lsb-release"
    4
    > 
    > liftM (length . lines ) . readFile $ "/etc/lsb-release"
    4
    > 
    > let countLinesOfFile = liftM (length . lines ) . readFile
    >
    > countLinesOfFile  "/etc/lsb-release"
    4
    > 
    
    > import Control.Monad.Identity 
    
    > liftM (+10) (Identity 20)
    Identity 30
    >
    

    1.3 liftM2

    Apply a function to two monads.

    liftM2 :: Monad m => (a -> b -> c) -> m a -> m b -> m c
    liftM2 f ma mb = do 
      a <- ma 
      b <- mb 
      return (f a b)
    
    liftM2 f ma mb = 
      ma >>= \a ->
      mb >>= \b -> 
      return (f a b)
    

    Examples:

    > import Control.Monad
    
    > liftM2 (+) (Just 3) (Just 4)
    Just 7
    > liftM2 (+) (Just 3) Nothing
    Nothing
    > liftM2 (+) Nothing  Nothing
    Nothing
    > 
    
    > liftM2 (+) (Right 10) (Right 20)
    Right 30
    >
    > liftM2 (+) (Right 10) (Left "Error parser failed")
    Left "Error parser failed"
    > 
    > liftM2 (+) (Left "Invalid number") (Right 20)
    Left "Invalid number"
    > 
    > liftM2 (+) (Left "Invalid number") (Left "Error parser failed")
    Left "Invalid number"
    > 
    
    > liftM2 (+) [1, 2, 3, 4] [9, 8, 10]
    [10,9,11,11,10,12,12,11,13,13,12,14]
    > 
    
    > import Control.Identity.Monad
    >
    > liftM2 (+) (Identity 20) (Identity 30)
    Identity 50
    >
    

    1.4 mapM

    Map each element of a structure to a monadic action, evaluate these actions from left to right, and collect the results. For a version that ignores the results see mapM_. (documentation)

    -- Haskell 7.6.3 
    -- 
    mapM :: Monad m => (a -> m b) -> [a] -> m [b]
    mapM f ts = sequence (map f ts)
    
    -- Haskell 7.10.2 
    -- 
    mapM :: (a -> m b) -> t a -> m (t b)
    mapM f ts = sequence (fmap f ts)
    

    Example:

    > import Control.Monad
    
    > import qualified Data.Maybe as M
    > import qualified System.Environment as E
    
    
    -- Signature in Haskell 7.6.3
    --
    > :t mapM
    mapM :: Monad m => (a -> m b) -> [a] -> m [b]
    > 
    
    > :t E.lookupEnv 
    E.lookupEnv :: String -> IO (Maybe String)
    > 
    
    -- Singature in Haskell 7.10.2 (mapM is generalized). 
    -- 
    > :t mapM
    mapM :: (Monad m, Traversable t) => (a -> m b) -> t a -> m (t b)
    > 
    
    > mapM E.lookupEnv ["HOME", "a1", "b1", "LANGUAGE", "PYTHONPATH"]
    [Just "/home/tux",Nothing,Nothing,Just "en_US",Just "/home/tux/lib"]
    > 
    
    > :t M.catMaybes 
    M.catMaybes :: [Maybe a] -> [a]
    > 
    
    > fmap M.catMaybes  $ mapM E.lookupEnv ["HOME", "a1", "b1", "LANGUAGE", "PYTHONPATH"]
    ["/home/tux","en_US","/home/tux/lib"]
    > 
    > :t fmap M.catMaybes  $ mapM E.lookupEnv ["HOME", "a1", "b1", "LANGUAGE", "PYTHONPATH"]
    fmap M.catMaybes  $ mapM E.lookupEnv ["HOME", "a1", "b1", "LANGUAGE", "PYTHONPATH"]
      :: IO [String]
    > 
    
    
    > let selector = \x -> if x > 10 then Just (3 + x) else Nothing
    >
    > :t selector 
    selector :: (Num a, Ord a) => a -> Maybe a
    > 
    
    > mapM selector (Just 20)
    Just (Just 23)
    > mapM selector Nothing
    Just Nothing
    > mapM selector (Just 3)
    Nothing
    > 
    
    > mapM selector [1, 2, 3, 4]
    Nothing
    > 
    
    > mapM selector [ 20, 30, 40]
    Just [23,33,43]
    >
    

    1.5 mapM_

    -- Haskell 7.6.3
    mapM_ :: Monad m => (a -> m b) -> [a] -> m ()
    mapM_ fn ta = sequence_ $ map fn ta 
    
    -- Haskell 7.10.2  - Generalized version of old mapM_
    --
    mapM_ :: (Monad m, Foldable t) => (a -> m b) -> t a -> m ()
    matM_ fn ta =  sequence_ $ fmap fn ta
    

    Example:

    > import Control.Monad
    
    > mapM_ putStrLn ["line 1", "line 3", "line 4"]
    line 1
    line 3
    line 4
    >  
    
    
    -- Lines bellow only Haskell 7.10.2 and compatible. 
    --
    > mapM_ putStrLn (Just "line")
    line
    >
    > mapM_ putStrLn Nothing
    > 
    
    > mapM_ putStrLn (Right "line")
    line
    > 
    > mapM_ putStrLn (Left "error BSOD 0x01002234")
    > 
    
    
    > sequence_ $ fmap putStrLn (Just "line")
    line
    > sequence_ $ fmap putStrLn Nothing
    > 
    > sequence_ $ fmap putStrLn ["line 1", "line 2", "line 3"]
    line 1
    line 2
    line 3
    >
    

    1.6 forM

    -- Haskell 7.10.2  
    -- 
    forM :: (Monad m, Traversable t) => t a -> (a -> m b) -> m (t b)
    forM = flip mapM
    

    Example:

    > import Control.Monad
    
    > forM  ["HOME", "LANGUAGE", "LC_TIME", "dummy"] E.lookupEnv  
    [Just "/home/tux",Just "en_US",Just "pt_BR.UTF-8",Nothing]
    > 
    > :t forM  ["HOME", "LANGUAGE", "LC_TIME", "dummy"] E.lookupEnv  
    forM  ["HOME", "LANGUAGE", "LC_TIME", "dummy"] E.lookupEnv
      :: IO [Maybe String]
    > 
    
    > forM  ["/etc/issue.net", "/etc/issue", "/proc/cmdline"] readFile
    ["Ubuntu 15.04\n","Ubuntu 15.04 \\n \\l\n\n","BOOT_IMAGE=/boot/vmlinuz-3.19.0-39-generic ..."]
    > 
    
    > forM   (Just "/etc/issue.net") readFile  
    Just "Ubuntu 15.04\n"
    >
    > :t forM   (Just "/etc/issue.net") readFile  
    forM   (Just "/etc/issue.net") readFile :: IO (Maybe String)
    > 
    
    > forM  Nothing readFile  
    Nothing
    > 
    
    
    > forM (Right "/etc/issue.net") readFile  
    Right "Ubuntu 15.04\n"
    > 
    > forM (Left "Fatal kernel error! System shutdown!!") readFile  
    Left "Fatal kernel error! System shutdown!!"
    >
    

    1.7 forM_

    > import Control.Monad
    
    -- Haskell 7.6.3 
    --
    forM_ :: (Monad m, Foldable t) => t a -> (a -> m b) -> m ()
    forM_ = flip mapM_
    
    > forM_ [1, 2, 3, 4, 5] $ \ n -> putStrLn $ show n
    1
    2
    3
    4
    5
    > 
    > forM_ [1, 2, 3, 4, 5] ( \ n -> putStrLn ( show n))
    1
    2
    3
    4
    5
    > 
    
    > forM_ (Just 10) $ \ n -> putStrLn $ show n
    10
    > 
    > forM_ Nothing $ \ n -> putStrLn $ show n
    > 
    
    > forM_ (Right 1000) $ \ n -> putStrLn $ show n
    1000
    > 
    > forM_ (Left "Fatal Kernel Error") $ \ n -> putStrLn $ show n
    >
    

    Example:

    
    

    1.8 replicateM

    Replicate a monad n times getting the results.

    replicateM :: Monad m => Int -> m a -> m [a]
    replicateM n x    = sequence (replicate n x)
    

    Example:

    > import Control.Monad
    
    > replicateM 4 (Just 3)
    Just [3,3,3,3]
    > 
    > replicateM 4 Nothing
    Nothing
    > 
    
    > replicateM 3 (Right 2)
    Right [2,2,2]
    > replicateM 3 (Left "Error: 0x902323EABC")
    Left "Error: 0x902323EABC"
    > 
    
    
    > replicateM 3 [1, 2]
    [[1,1,1],[1,1,2],[1,2,1],[1,2,2],[2,1,1],[2,1,2],[2,2,1],[2,2,2]]
    > 
    
    > :t replicateM 3 getLine
    replicateM 3 getLine :: IO [String]
    > 
    >
    > replicateM 3 getLine
    line1
    line2
    line3
    ["line1","line2","line3"]
    > 
    
    > lines <- replicateM 3 getLine
    line1
    line2
    line3
    > lines
    ["line1","line2","line3"]
    > :t lines
    lines :: [String]
    > 
    
    > import Control.Monad.Identity 
    
    > replicateM 6 (Identity 2)
    Identity [2,2,2,2,2,2]
    >
    

    1.9 replicateM_

    Like replicateM, but throw away the result.

    replicateM_ :: Monad m => Int -> m a -> m ()
    replicateM_ n x   = sequence_ (replicate n x)
    

    Example:

    > import Control.Monad
    
    > replicateM_ 3 (putStrLn "hello world")
    hello world
    hello world
    hello world
    > 
    > :t replicateM_ 3 (putStrLn "hello world")
    replicateM_ 3 (putStrLn "hello world") :: IO ()
    >
    

    1.10 sequence

    Evaluate each monadic action in the structure from left to right, and collect the results. For a version that ignores the results see sequence_.

    -- Implementation Haskell 7.6.3
    -- 
    -- Source: http://kodu.ut.ee/~varmo/FP2007/slides/loeng13.pdf
    -- 
    sequence :: Monad m => [m a] -> m [a]
    sequence = foldr mcons (return [])
        where 
           mcons p q = 
              p >>= \x -> 
              q >>= \y -> 
               return (x:y)
    

    Example:

    > import Control.Monad
    
    -- Haskell 7.6.3 
    --
    > :t sequence
    sequence :: Monad m => [m a] -> m [a]
    > 
    
    -- Haskell 7.10.2 
    -- 
    > :t sequence
    sequence :: (Monad m, Traversable t) => t (m a) -> m (t a)
    > 
    
    > sequence [[1], [2, 3, 4], [], [4], [], [], [20, 30]]
    []
    > sequence [[1], [2, 3, 4],  [4],  [20, 30]]
    [[1,2,4,20],[1,2,4,30],[1,3,4,20],[1,3,4,30],[1,4,4,20],[1,4,4,30]]
    > 
    > sequence [[2, 3, 4],  [4],  [20, 30]]
    [[2,4,20],[2,4,30],[3,4,20],[3,4,30],[4,4,20],[4,4,30]]
    > 
    
    -- Haskell 7.6.3 (Sequence only works for lists)
    -- 
    > sequence (Just [1, 2, 3, 4])
    
    <interactive>:8:11:
        Couldn't match expected type `[m0 a0]'
                    with actual type `Maybe [t0]'
        In the return type of a call of `Just'
    
    --- Haskell 7.10.2 (Sequence was generalized)
    ---
    > sequence (Just [1, 2, 3, 4])
    [Just 1,Just 2,Just 3,Just 4]
    > 
    
    
    
    > sequence [Just 1, Just 2, Just 3, Just 4] 
    Just [1,2,3,4]
    > 
    >
    > sequence [Just 1, Just 2, Just 3, Nothing, Just 4, Nothing] 
    Nothing
    > 
    
    > sequence [Right 1, Right 2, Right 3, Right 4]
    Right [1,2,3,4] 
    >
    > sequence [Right 10, Left "Error 0", Left "Error 1", Left "Error 2"] 
    Left "Error 0"
    > 
    > sequence [Right 10, Right 20, Left "Error 1", Right 4] 
    Left "Error 1"
    > 
    
    > :t [putStrLn "line1", putStrLn "line2", putStrLn "line3"]
    [putStrLn "line1", putStrLn "line2", putStrLn "line3"] :: [IO ()]
    > 
    > sequence [putStrLn "line1", putStrLn "line2", putStrLn "line3"]
    line1
    line2
    line3
    [(),(),()]
    > 
    
    > let inputNunmber = getLine >>= \ str -> return $ (read str :: Integer)
    > 
    > :t inputNunmber 
    inputNunmber :: IO Integer
    > 
    > let actions = [inputNunmber, inputNunmber, inputNunmber]
    > :t actions 
    actions :: [IO Integer]
    > 
    
     -- Only works in the repl (<-) to extract content from IO Monad.
    
    > out <- sequence actions 
    23
    100
    200
    > out
    [23,100,200]
    > :t out
    out :: [Integer]
    > 
    
    > sequence actions 
    200
    30
    50
    [200,30,50]
    > :t sequence actions 
    sequence actions :: IO [Integer]
    > 
    
    > import Control.Monad.Identity
    >
    > sequence [Identity 20, Identity 10, Identity 30]
    Identity [20,10,30]
    >
    

    1.11 sequence_

    Evaluate each monadic action in the structure from left to right, and ignore the results. For a version that doesn't ignore the results see sequence. (documentation).

    -- Haskell 7.6.3. Most of texts and lectures notes refers 
    -- to the old implementation of sequence_. 
    --
    sequence_ :: Monad m => [m a] -> m ()
    sequence_ = foldr (>>) (return ())
    
    -- Haskell 7.10.2
    sequence_ :: (Monad m, Foldable t) => t (m a) -> m ()
    

    Examples:

    > import Control.Monad
    
    (>>) :: Monad m => m a -> m b -> m b
    (>>) ma mb = 
         ma >>= \ _ ->  mb 
    
    > putStrLn "hello world" >> putStrLn "Hola mundo"
    hello world
    Hola mundo
    > 
    
    --  Haskell 7.10.2 and Haskell 7.6.3 
    --
    > sequence_ [putStrLn "Line 1", putStrLn "Line 2", putStrLn "Line 3"]
    Line 1
    Line 2
    Line 3
    > 
    
    --  Haskell 7.10.2 only. 
    --
    > sequence_ $ Just (putStrLn "Hello world")
    Hello world
    > 
    > :t sequence_ $ Just (putStrLn "Hello world")
    sequence_ $ Just (putStrLn "Hello world") :: IO ()
    > 
    
    > sequence_ $ Just ([1, 2, 3, 4, 5])
    [(),(),(),(),()]
    > 
    > sequence_ $ Nothing
    >
    

    1.12 foldM

    -- Haskell 7.6.3
    -- 
    foldM :: Monad m => (a -> b -> m a) -> a -> [b] -> m a
    foldM f a []     = return a 
    foldM f a (x:xs) =  f a x >>= \ fax -> foldM f fax xs
    
    -- Haskell 7.10.2 
    --
    foldM  :: (Monad m, Foldable t) => (b -> a -> m b) -> b -> t a -> m b
    foldM = ???
    
    
    -- foldM Intutition 
    
    foldM f acc0  [x0, x1, x2, ... xn] = do  acc1 <- f acc0 x0 
                                             acc2 <- f acc1 x1 
                                             acc3 <- f acc2 x2
                                             ...
                                             f an xn
    

    Example:

    > import Control.Monad
    
    > import Control.Identity.Monad
    
    > foldM (\acc x -> Identity (10 * acc + x)) 0 [1, 2, 3, 4, 5]
    Identity 12345
    > 
    
    > foldM (\acc x -> Just (10 * acc + x)) 0 [1, 2, 3, 4, 5]
    Just 12345
    > 
    
    -- If the functions returns Nothing, the whole computation fails:
    -- returns Nothing 
    -- 
    > foldM (\acc x -> if x > 3 then Nothing else Just (10 * acc + x)) 0 [1, 2, 3, 4, 5]
    Nothing
    > 
    
    > foldM (\acc x -> return (10 * acc + x) :: IO Integer) 0 [1, 2, 3, 4, 5]
    12345
    > :t foldM (\acc x -> return (10 * acc + x) :: IO Integer) 0 [1, 2, 3, 4, 5]
    foldM (\acc x -> return (10 * acc + x) :: IO Integer) 0 [1, 2, 3, 4, 5]
      :: IO Integer
    >
    

    Author: nobody

    Created: 2018-06-17 Sun 02:37

    Emacs 25.3.1 (Org mode 8.2.10)

    Validate