$ ghci 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. // How can we mix normal function results and inputs, and values // indicating failure? How can we make a function like sq // do a special thing for an error value? Prelude> let sq x = x*x Prelude> sq 5 25 // Haskell has a special type for this, Maybe. The intended meaning of // Maybe is that a value of this type is either a real value or the special // value Nothing. In order to make this type work for any kind of a real value, // it is defined with a type parameter (so that you can have 'Maybe Int', 'Maybe String', // 'Maybe (List a)' or any other kind of value. // // For Haskell's pattern matching, the real value is wrapped up in another type // constructor, whose only purpose is to be an alternative to Nothing in patterns. // Think of it as a sort of a "box" around the real value, so that you can be // sure you are getting the real value and can match it out. "Just" is a somewhat // non-intuitive name, perhaps "Real" or "Boxed" would be more intuitive. Prelude> :t Nothing Nothing :: Maybe a Prelude> :i Maybe data Maybe a = Nothing | Just a -- Defined in ‘Data.Maybe’ instance Eq a => Eq (Maybe a) -- Defined in ‘Data.Maybe’ instance Monad Maybe -- Defined in ‘Data.Maybe’ instance Functor Maybe -- Defined in ‘Data.Maybe’ instance Ord a => Ord (Maybe a) -- Defined in ‘Data.Maybe’ instance Read a => Read (Maybe a) -- Defined in ‘GHC.Read’ instance Show a => Show (Maybe a) -- Defined in ‘GHC.Show’ // So, how to use this type to program consistently with it? // First try. Can we just add a pattern for Nothing? > :set +m Prelude> let sq Nothing = Nothing Prelude| sq x = x*x Prelude| // So far so good, but the type alone hints it won't work: we // meant to a to be Num, not (Maybe a). This inference for // the type of x comes from x being a thing that can be a Nothing, // so x is a 'Maybe t' from some type t; and then x participates // in multiplication, so that 'Maybe t' must be a Num! Prelude> :t sq sq :: Num (Maybe a) => Maybe a -> Maybe a // This fails: Prelude> sq 5 :21:1: No instance for (Num (Maybe a0)) arising from a use of ‘it’ In a stmt of an interactive GHCi command: print it // So let's try again. Now we make sure that the argument is either a Nothing or a // number "boxed" with Just: Prelude> :set +m Prelude> let sq Nothing = Nothing Prelude| sq (Just x) = x*x // This doesn't quite work: the types don't unify on the right-hand side: Prelude> sq 5 :9:1: No instance for (Num (Maybe (Maybe a0))) arising from a use of ‘it’ In a stmt of an interactive GHCi command: print it Prelude> sq Nothing :10:1: No instance for (Num (Maybe a0)) arising from a use of ‘it’ In a stmt of an interactive GHCi command: print it // Not surprisingly, the type of this function suggests it has a problem // (think how it arises and where the double Maybe comes from!): Prelude> :t sq sq :: Num (Maybe a) => Maybe (Maybe a) -> Maybe a // Now this works: Prelude> let sq Nothing = Nothing Prelude| sq (Just x) = Just (x*x) Prelude> sq Nothing Nothing Prelude> sq (Just 5) Just 25 Prelude> :t sq sq :: Num a => Maybe a -> Maybe a // So sq works, but needs boxed numbers. We can compose it with other // functions that work on boxed numbers: // but of course I mistype and forget the ()s around the pattern first, argh: Prelude> let plus1 Nothing = Nothing Prelude| plus1 Just x = Just (x+1) Prelude| :17:5: Equations for ‘plus1’ have different numbers of arguments :17:5-27 :18:5-30 // Fixed: Prelude> let plus1 Nothing = Nothing Prelude| plus1 (Just x) = Just (x+1) Prelude| Prelude> plus1 (sq Nothing) Nothing Prelude> plus1 (sq (Just 5)) Just 26 // We can use function composition for slicker syntax -- but remember the relative // precedence of operators! Prelude> plus1 . sq (Just 5) :25:9: Couldn't match expected type ‘a -> Maybe a1’ with actual type ‘Maybe a0’ Relevant bindings include it :: a -> Maybe a1 (bound at :25:1) Possible cause: ‘sq’ is applied to too many arguments In the second argument of ‘(.)’, namely ‘sq (Just 5)’ In the expression: plus1 . sq (Just 5) Prelude> (plus1 . sq) (Just 5) Just 26 Prelude> f = plus1 . sq :27:3: parse error on input ‘=’ // Now this works, as do "(plus1 . sq) (Just 5)" and "plus1 . sq $ Just 5" Prelude> let f = plus1 . sq Prelude| Prelude> f (Just 5) Just 26 // One common example of wanting to produce and pass along a special failure-indicating value // is lookup of element index in a list (what to return if the element is not there?): Prelude> import Data.List Prelude Data.List> :t elemIndex elemIndex :: Eq a => a -> [a] -> Maybe Int // 0-based index or nothing: Prelude Data.List> elemIndex 5 [1,2,4,5] Just 3 Prelude Data.List> elemIndex 6 [1,2,4,5] Nothing Prelude Data.List> sq (elemIndex 6 [1,2,4,5]) Nothing Prelude Data.List> elemIndex "x" ["x", "y", "z"] Just 0 Prelude Data.List> elemIndex "y" ["x", "y", "z"] Just 1 Prelude Data.List> elemIndex "z" ["x", "y", "z"] Just 2 Prelude Data.List> sq (elemIndex "z" ["x", "y", "z"]) Just 4 Prelude Data.List> sq (elemIndex "foo" ["x", "y", "z"]) Nothing Prelude Data.List> plus1 (sq (elemIndex "foo" ["x", "y", "z"])) Nothing Prelude Data.List> plus1 (sq (elemIndex "z" ["x", "y", "z"])) Just 5 // Suggestion: rewrite it using "." without parens. It's called the applicative style. // Let's get some helper functions, for simple operations such as unboxing. // See https://hackage.haskell.org/package/base-4.9.0.0/docs/src/Data.Maybe.html Prelude Data.List> :i Maybe data Maybe a = Nothing | Just a -- Defined in ‘Data.Maybe’ instance Eq a => Eq (Maybe a) -- Defined in ‘Data.Maybe’ instance Monad Maybe -- Defined in ‘Data.Maybe’ instance Functor Maybe -- Defined in ‘Data.Maybe’ instance Ord a => Ord (Maybe a) -- Defined in ‘Data.Maybe’ instance Read a => Read (Maybe a) -- Defined in ‘GHC.Read’ instance Show a => Show (Maybe a) -- Defined in ‘GHC.Show’ // typo: Prelude Data.List> import Maybe.Data : Could not find module ‘Maybe.Data’ It is not a module in the current program, or in any known package. // OK: Prelude Data.List> import Data.Maybe Prelude Data.List Data.Maybe> fromJust( plus1 (sq (elemIndex "z" ["x", "y", "z"]))) 5 Prelude Data.List Data.Maybe> fromJust( plus1 (sq (elemIndex "z" ["x", "y", "z"]))) + 100 105 // But writing a new function with a special case for passing Nothing for every // little bit of arithmetic or string operation is boring. We want to write code with normal "unboxed" // numbers or strings, or whatever may fail but we want to pipeline in a series of // function calls. // >>= (so-called "monadic bind") gives us a way: Prelude Data.List Data.Maybe> :i >>= class Monad (m :: * -> *) where (>>=) :: m a -> (a -> m b) -> m b ... -- Defined in ‘GHC.Base’ infixl 1 >>= // So we start with a boxed value ("m a", m was Maybe in our examples above), take a function // from type a to some type b---but boxed!---and out comes "m b" (of course, this is // what the function returns, being "a -> m b". // So this doesn't quite work: we get the first argument of >>= right, but not the second. // Remember, (+) 1 is a function from num to a num. But its result type is not boxed. Prelude Data.List Data.Maybe> (Just 5) >>= (+) 1 :50:1: No instance for (Num (Maybe b0)) arising from a use of ‘it’ In a stmt of an interactive GHCi command: print it Prelude Data.List Data.Maybe> (Just 5) >>= sq :51:1: No instance for (Num (Maybe b0)) arising from a use of ‘it’ In a stmt of an interactive GHCi command: print it // This works: Prelude Data.List Data.Maybe> (Just 5) >>= Just . ((+) 1) Just 6 // Same as: Prelude Data.List Data.Maybe> (Just 5) >>= Just . (+) 1 Just 6 // Can we use it with sq? This doesn't work, wrong type of x. Being an argument to fromJust // infers x as being a Maybe, not a number! Prelude Data.List Data.Maybe> (Just 5) >>= (\x -> sq (fromJust x)) :52:1: No instance for (Num (Maybe (Maybe b0))) arising from a use of ‘it’ In a stmt of an interactive GHCi command: print it Prelude Data.List Data.Maybe> :t (\ x -> sq (fromJust x)) (\ x -> sq (fromJust x)) :: Num a => Maybe (Maybe a) -> Maybe a // This works: (we need boxing added, not removed, to match the >>= type signature) Prelude Data.List Data.Maybe> (Just 5) >>= \x -> sq (Just x) Just 25 // OK, let's build pipelines that can take Nothing: // Definition of >>= for Maybe: // https://hackage.haskell.org/package/base-4.9.0.0/docs/src/GHC.Base.html#line-664 // (if a real value, unbox and apply function; if Nothing, pass it through) Prelude Data.List Data.Maybe> :t elemIndex elemIndex :: Eq a => a -> [a] -> Maybe Int Prelude Data.List Data.Maybe> elemIndex "b" ["a", "b", "c"] Just 1 Prelude Data.List Data.Maybe> elemIndex "b" ["a", "b", "c"] >>= (\x -> Just (x*x)) >>= (\x -> Just(x + 1)) Just 2 Prelude Data.List Data.Maybe> elemIndex "c" ["a", "b", "c"] >>= (\x -> Just (x*x)) >>= (\x -> Just(x + 1)) Just 5 Prelude Data.List Data.Maybe> elemIndex "x" ["a", "b", "c"] >>= (\x -> Just (x*x)) >>= (\x -> Just(x + 1)) Nothing Prelude Data.List Data.Maybe> elemIndex "x" ["a", "b", "c"] >>= (\x -> Just (x*x)) >>= (\x -> Just(x + 1)) Nothing // Note, pipelines are lazy: Prelude Data.List Data.Maybe> Nothing >>= (error "bang") Nothing // Also note, Maybe derives Eq (so == works on boxed values) and Ord (so > and < work on them) // To see the definition: https://hackage.haskell.org/package/base-4.9.0.0/docs/src/GHC.Base.html#Maybe Prelude Data.List Data.Maybe> (Just 5) == (Just 5) True Prelude Data.List Data.Maybe> (Just 5) == Nothing False Prelude Data.List Data.Maybe> (Just 5) == (Just 3) False Prelude Data.List Data.Maybe> (Just 5) < (Just 3) False Prelude Data.List Data.Maybe> (Just 5) > (Just 3) True Prelude Data.List Data.Maybe> (Just 1) > (Just 3) False Prelude Data.List Data.Maybe> (Just 1) < (Just 3) True Prelude Data.List Data.Maybe> (Just 1) < Nothing False Prelude Data.List Data.Maybe> (Just 1) > Nothing True // type error, of course: Prelude Data.List Data.Maybe> 0 > Nothing :70:1: No instance for (Num (Maybe a0)) arising from the literal ‘0’ In the first argument of ‘(>)’, namely ‘0’ In the expression: 0 > Nothing In an equation for ‘it’: it = 0 > Nothing :70:3: No instance for (Ord a0) arising from a use of ‘>’ The type variable ‘a0’ is ambiguous Note: there are several potential instances: instance Integral a => Ord (GHC.Real.Ratio a) -- Defined in ‘GHC.Real’ instance Ord Integer -- Defined in ‘integer-gmp:GHC.Integer.Type’ instance Ord a => Ord (Maybe a) -- Defined in ‘Data.Maybe’ ...plus 41 others In the expression: 0 > Nothing In an equation for ‘it’: it = 0 > Nothing // typo: Prelude Data.List Data.Maybe> (Just 0) > Nothin :71:12: Not in scope: data constructor ‘Nothin’ Perhaps you meant ‘Nothing’ (imported from Prelude) Prelude Data.List Data.Maybe> (Just 0) > Nothing True Prelude Data.List Data.Maybe> (Just -1) > Nothin :73:13: Not in scope: data constructor ‘Nothin’ Perhaps you meant ‘Nothing’ (imported from Prelude) // syntax of - is not what we might expect; it needs ()s Prelude Data.List Data.Maybe> (Just -1) > Nothing :74:13: Couldn't match expected type ‘a0 -> Maybe a0’ with actual type ‘Maybe a1’ In the second argument of ‘(>)’, namely ‘Nothing’ In the expression: (Just - 1) > Nothing Prelude Data.List Data.Maybe> (Just (-1)) > Nothing True // Constant function (of arity 1): Prelude Data.List Data.Maybe> let f = \ x -> 5 Prelude Data.List Data.Maybe| // No default string representation for functions Prelude Data.List Data.Maybe> f :79:1: No instance for (Show (t0 -> a0)) arising from a use of ‘print’ In a stmt of an interactive GHCi command: print it // but it works: Prelude Data.List Data.Maybe> f 0 5 Prelude Data.List Data.Maybe> f 1 5 Prelude Data.List Data.Maybe> f 2 5 Prelude Data.List Data.Maybe> f 3 5 Prelude Data.List Data.Maybe> let f = \ _ -> 5 Prelude Data.List Data.Maybe| // >> is a variant of >>= that ignores any real 1st argument, but still treats Nothing specially: Prelude Data.List Data.Maybe> Nothing >> (Just 5) Nothing Prelude Data.List Data.Maybe> (Just 1) >> (Just 5) Just 5 Prelude Data.List Data.Maybe> (Just 0) >> (Just 5) Just 5 Prelude Data.List Data.Maybe> (Just 1000000000) >> (Just 5) Just 5 // And it's lazy too: Prelude Data.List Data.Maybe> Nothing >> (error "bang") Nothing Prelude Data.List Data.Maybe> Nothing >> (error "bang") >> (error "foo") Nothing Prelude Data.List Data.Maybe> Nothing >> (error "bang") >>= (error "foo") >>= (error "kaboom") Nothing // Mind syntax of infix functions when asking for their type: Prelude Data.List Data.Maybe> :t >>= :1:1: parse error on input ‘>>=’ Prelude Data.List Data.Maybe> :t (>>=) (>>=) :: Monad m => m a -> (a -> m b) -> m b Prelude Data.List Data.Maybe> :i >>= class Monad (m :: * -> *) where (>>=) :: m a -> (a -> m b) -> m b ... -- Defined in ‘GHC.Base’ infixl 1 >>= // ^^^^^^^^^ note lowest precedence Prelude Data.List Data.Maybe> elemIndex "x" ["a", "b", "c"] >>= (\x -> Just (x*x)) >>= (\x -> Just(x + 1)) Nothing Prelude Data.List Data.Maybe> elemIndex "x" ["a", "b", "c"] >>= (\x -> Just (x*x)) >>= (\x -> Just(x + 1)) Nothing Prelude Data.List Data.Maybe> elemIndex "c" ["a", "b", "c"] >>= (\x -> Just (x*x)) >>= (\x -> Just(x + 1)) Just 5 Prelude Data.List Data.Maybe> elemIndex "c" ["a", "b", "c"] >>= (\x -> Just (x*x)) >>= Just . (+) 1 Just 5 Prelude Data.List Data.Maybe> elemIndex "c" ["a", "b", "c"] >>= Just . (\x -> (x*x)) >>= Just . (+) 1 Just 5 // Mind infix syntax again: Prelude Data.List Data.Maybe> :t . :1:1: parse error on input ‘.’ Prelude Data.List Data.Maybe> :t (.) (.) :: (b -> c) -> (a -> b) -> a -> c Prelude Data.List Data.Maybe> :i . (.) :: (b -> c) -> (a -> b) -> a -> c -- Defined in ‘GHC.Base’ infixr 9 . // ^^^^^^ note precedence 9! This means >>= lets . and almost everything else apply first: Prelude Data.List Data.Maybe> elemIndex "c" ["a", "b", "c"] >>= Just . (*) 10 >>= Just . (+) 1 Just 21 Prelude Data.List Data.Maybe> elemIndex "z" ["a", "b", "c"] >>= Just . (*) 10 >>= Just . (+) 1 Nothing [UPDATED: do notation]: The same pipeline as above in the do notation: Prelude Data.List Data.Maybe> do i <- elemIndex "c" ["a", "b", "c"] ; i1 <- Just (i * 10) ; Just (i1 + 1) Prelude Data.List Data.Maybe| Just 21 // This can be written more generically. Since elemIndex is know to return a "Maybe Int", instead // of explicitly wrapping the results of * and + in "Just", you can say "wrap them in whatever // type the >>= pipeline gets" instead, with "return". This "return" has nothing to do with // C's or Java's return operator; instead, it created a boxed version of the value passed to it, // boxing it up into whatever type the rest of the pipeline infers: Prelude Data.List Data.Maybe> do i <- elemIndex "c" ["a", "b", "c"] ; i1 <- return (i * 10) ; return (i1 + 1) Prelude Data.List Data.Maybe| Just 21 //////////////////////////// Functors //////////////////////////// // // If a type is an instance of "Functor", it means that for its constructors from // another type, functions from that type can be "lifted". That is, if you // have a function that makes b from a (i.e., of type "a -> b") , then you // can make a function that works on the constructed objects too. // For example, if you have (a -> b), you also then have ([a] -> [b]) and // (Maybe a -> Maybe b). The original function is lifted to the new argument types // by applying "fmap". Definitions for lists and Maybe (both from GHC.Base link above): // instance Functor [] where // fmap = map // instance Functor Maybe where // fmap _ Nothing = Nothing // fmap f (Just a) = Just (f a) // For lists it's just map, partially applied: Prelude Data.List Data.Maybe> let sq x = x*x Prelude Data.List Data.Maybe| Prelude Data.List Data.Maybe> map sq [1,2,3,4,5] [1,4,9,16,25] Prelude Data.List Data.Maybe> :t map sq map sq :: Num b => [b] -> [b] Prelude Data.List Data.Maybe> :t map map :: (a -> b) -> [a] -> [b] Prelude Data.List Data.Maybe> map show [1,2,3,4,5] ["1","2","3","4","5"] Prelude Data.List Data.Maybe> :t map show map show :: Show a => [a] -> [String] Prelude Data.List Data.Maybe> let ind_sq x = elemIndex x ["a", "b", "c"] >>= Just . (\x -> x*x) Prelude Data.List Data.Maybe| Prelude Data.List Data.Maybe> :t ind_sq ind_sq :: [Char] -> Maybe Int Prelude Data.List Data.Maybe> ind_sq "c" Just 4 Prelude Data.List Data.Maybe> ind_sq "z" Nothing Prelude Data.List Data.Maybe> :t map ind_sq map ind_sq :: [[Char]] -> [Maybe Int] Prelude Data.List Data.Maybe> map ind_sq ["z", "t", "c"] [Nothing,Nothing,Just 4] // So since Maybe has fmap defined (a.k.a. is a "Functor" instance), // we could have definded our sq that operates on Maybe's and understands // how to pass Nothings as follows: Prelude Data.List> let sq x = x*x Prelude Data.List| // Yeah, can't show type of functions... Prelude Data.List> fmap sq :38:1: No instance for (Show (f0 b0 -> f0 b0)) arising from a use of ‘print’ In a stmt of an interactive GHCi command: print it // but its type is right: Prelude Data.List> :t fmap sq fmap sq :: (Num b, Functor f) => f b -> f b Prelude Data.List> (fmap sq) (Just 5) Just 25 Prelude Data.List> (fmap sq) Nothing Nothing // Or simpler: Prelude Data.List> let sq = fmap (\x -> x*x) Prelude Data.List| Prelude Data.List> sq Nothing Nothing Prelude Data.List> sq (Just 5) Just 25 Prelude Data.List>