Module: Control.Monad
Table of Contents
1 Control.Monad - Monad Combinators
This module provides functions to manipulate monads.
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 >