-- Defining a "direct sum" of numbers and strings, which would -- have a function that adds or concatenates its arguments, -- depending on what they are. -- First try, incomplete: Prelude Data.Char> let f (Left x) (Left y) = (x+y) Prelude Data.Char> :t f f :: Num a => Either a t -> Either a t1 -> a -- Note that nothing could be inferred about the second type, because -- type inference algorithm lacks any clues from operations on it. -- Hence we have t and t1 , which could be different, from different -- definitions of Either, even. -- But the above will always make us a numeric. That's not what we want--- -- we want to add numbers, but concat strings. Prelude Data.Char> let f (Left x) (Left y) = Left (x+y) Prelude Data.Char> :t f f :: Num a => Either a t -> Either a t1 -> Either a b -- Type error: Prelude Data.Char> let { f (Left x) (Left y) = Left (x+y) ; f (Right x) (Right y) = x ++ y } :16:66: Couldn't match expected type ‘Either a b’ with actual type ‘[a1]’ Relevant bindings include y :: [a1] (bound at :16:61) x :: [a1] (bound at :16:51) f :: Either a [a1] -> Either a [a1] -> Either a b (bound at :16:7) In the expression: x ++ y In an equation for ‘f’: f (Right x) (Right y) = x ++ y Prelude Data.Char> :t (++) (++) :: [a] -> [a] -> [a] -- Finally, correct: Prelude Data.Char> let { f (Left x) (Left y) = Left (x+y) ; f (Right x) (Right y) = Right (x ++ y) } Prelude Data.Char> f (Left 3) (Left 4) Left 7 Prelude Data.Char> f (Right "foo") (Right "bar") Right "foobar" -- Exploring map and fmap: Prelude Data.Char> :t map map :: (a -> b) -> [a] -> [b] Prelude Data.Char> \x -> x * x :22:1: No instance for (Show (a0 -> a0)) arising from a use of ‘print’ In a stmt of an interactive GHCi command: print it -- that's right, Haskell doesn't know how to print lambda's internals -- This syntax error is trickier. What happened here? Hint: look at -- the precedence of the operators (with :i) Prelude Data.Char> \x -> x * x $ 10 :23:1: No instance for (Show ((s0 -> t0) -> t0)) arising from a use of ‘print’ In a stmt of an interactive GHCi command: print it --- Finally: Prelude Data.Char> (\x -> x * x) $ 10 100 Prelude Data.Char> (\x -> x * x) 10 100 Prelude Data.Char> :t (\x -> x * x) (\x -> x * x) :: Num a => a -> a Prelude Data.Char> let sq= (\x -> x * x) Prelude Data.Char> :t sq sq :: Num a => a -> a Prelude Data.Char> sq 10 100 Prelude Data.Char> map sq [1,2, 4] [1,4,16] -- Map takes a function and makes a function on the list type: Prelude Data.Char> :t map sq map sq :: Num b => [b] -> [b] -- fmap does this for more general types (any type that defines fmap!) Prelude Data.Char> :t fmap fmap :: Functor f => (a -> b) -> f a -> f b Prelude Data.Char> :t show show :: Show a => a -> String Prelude Data.Char> :t map map :: (a -> b) -> [a] -> [b] Prelude Data.Char> fmap (++"!") ["foo", "bar"] ["foo!","bar!"] Prelude Data.Char> map (++"!") ["foo", "bar"] ["foo!","bar!"] -- fmap is defined for Data.Maybe, and so makes a squaring -- function for Maybe on numerics, with no extra work! Prelude Data.Char> let sqm = fmap sq Prelude Data.Char> :t sqm sqm :: (Num b, Functor f) => f b -> f b Prelude Data.Char> sqm (Just 2) Just 4 Prelude Data.Char> sqm (Just 10) Just 100 -- And it knows how to handle Nothing, too (it's a part of the fmap -- instance definition for Maybe): Prelude Data.Char> sqm Nothing Nothing -- This works for any constructed types: Prelude Data.Char> map sqm [ Just 1, Just 2, Just 3, Nothing, Just 5] [Just 1,Just 4,Just 9,Nothing,Just 25] Prelude Data.Char> map (elemIndex 'x') [ "x", "yzx", "t" ] -- Oops, lacking the definition. :43:7: Not in scope: ‘elemIndex’ Prelude Data.Char> import Data.List Prelude Data.Char Data.List> map (elemIndex 'x') [ "x", "yzx", "t" ] [Just 0,Just 2,Nothing] -- Now let's look at >>= , which is defined in an instance of Monad for Maybe: Prelude Data.Char Data.List> :t (>>=) (>>=) :: Monad m => m a -> (a -> m b) -> m b Prelude Data.Char Data.List> fmap (elemIndex 'x') [ "x", "yzx", "t" ] [Just 0,Just 2,Nothing] Prelude Data.Char Data.List> :t (elemIndex 'x') (elemIndex 'x') :: [Char] -> Maybe Int -- Note the type definition. fmap works for anything that defines "fmap" -- (i.e., for any type that adds an instance definition of it, a.k.a. the Functor -- typeclass) Prelude Data.Char Data.List> :t fmap (elemIndex 'x') fmap (elemIndex 'x') :: Functor f => f [Char] -> f (Maybe Int) -- This is what is behind our pipeline Prelude Data.Char Data.List> elemIndex "z" ["y" , "x", "z" ] >>= Just . ((+) 1) >>= Just . ((*) 2) Just 6 Prelude Data.Char Data.List> :i (>>=) class Monad (m :: * -> *) where (>>=) :: m a -> (a -> m b) -> m b ... -- Defined in ‘GHC.Base’ infixl 1 >>= --- Let's explore IO: $ ghc rock.hs [1 of 1] Compiling Main ( rock.hs, rock.o ) Linking rock ... $ ./rock Hello, what's your name? Sergey Hey Sergey, you rock! GHCi, version 7.8.3: http://www.haskell.org/ghc/ :? for help Loading package ghc-prim ... linking ... done. Loading package integer-gmp ... linking ... done. Loading package base ... linking ... done. Prelude> :l rock.hs [1 of 1] Compiling Main ( rock.hs, interpreted ) Ok, modules loaded: Main. *Main> main Hello, what's your name? Foo Hey Foo, you rock! *Main> :t main main :: IO () *Main> :t getLine getLine :: IO String Prelude System.IO> :t putStrLn putStrLn :: String -> IO () Prelude> :t (>>=) (>>=) :: Monad m => m a -> (a -> m b) -> m b -- Observe the "desugared" version of rock.hs in one line. Note how -- the above types fit the type signature of >>= Prelude> import System.IO -- First try, syntax error. What went wrong? Prelude System.IO> getLine >>= \x -> putStrLn x ++ " you rock!" >> putStrLn "Bye!" :5:19: Couldn't match expected type ‘[Char]’ with actual type ‘IO ()’ In the first argument of ‘(++)’, namely ‘putStrLn x’ In the first argument of ‘(>>)’, namely ‘putStrLn x ++ " you rock!"’ :5:19: Couldn't match type ‘[]’ with ‘IO’ Expected type: IO Char Actual type: [Char] In the first argument of ‘(>>)’, namely ‘putStrLn x ++ " you rock!"’ In the expression: putStrLn x ++ " you rock!" >> putStrLn "Bye!" In the second argument of ‘(>>=)’, namely ‘\ x -> putStrLn x ++ " you rock!" >> putStrLn "Bye!"’ -- Ah, how many times do I have to remind myself that parens go around -- expressions that are meant to be args to functions? Now fixed: Prelude System.IO> getLine >>= \x -> putStrLn (x ++ " you rock!") >> putStrLn "Bye!" Bar Bar you rock! Bye! -- Note that we use both >>= and >> . The former to catch the input (which is fed -- right into our lambda; in "do" notation, <- would have hidden it), >> to just -- do the next thing (print "Bye!") when we don't care about catching anything -- from the first argument of >> (pure chaining).