Haskell === ###### tags: `Programming Language` ## Functional Programming - [The Foundations of Functional Concurrency](https://freecontent.manning.com/the-foundations-of-functional-concurrency/) ## Reference - [Hoogle](https://www.haskell.org/hoogle/) - [Directory listing for base-4.3.1.0 documentation](http://hackage.haskell.org/package/base-4.3.1.0/docs/src/) - [Zvon - Haskell Reference](http://zvon.org/other/haskell/Outputprelude/) ## [Write You a Haskell](http://dev.stephendiehl.com/fun/index.html) - [Parsing](http://dev.stephendiehl.com/fun/002_parsers.html) ## [HackerRank](https://www.hackerrank.com/domains/fp/intro) ``` > :info Integral instance Integral Int > :t fromIntegral fromIntegral :: (Integral a, Num b) => a -> b > :info Num instance Num Double instance Num Int instance Num Float ``` ## [Functional Thursday](https://www.youtube.com/channel/UC-rw-O1QGamq6pUsDRkwgpw) - [The Road To Monad Transformers](https://www.slideshare.net/plisek/the-road-to-monad-transformers) ## [Introduction to Functional Programming](https://courses.edx.org/courses/course-v1:DelftX+FP101x+3T2015/course/) - [Programming in Haskell](http://www.cs.nott.ac.uk/~pszgmh/pih.html) - [The Hugs 98 User's Guide](https://www.haskell.org/hugs/pages/users_guide/index.html) ``` hugs -Evi test.hs ``` ### First Steps ``` > (+) 2 2 4 > 5 `div` 3 1 > :t drop drop :: Int -> [a] -> [a] > tail [1, 2, 3] [2, 3] > :t (:) (:) :: a -> [a] -> [a] ``` Note: ```::``` is type annotation. ### Types and Type Classes Syntactically well-formed expression has a type and that type is calculated by the compiler at **compile-time** using a process called **type inference**. **Type errors** are also in Haskell found at **compile-time**. ```Int```s are fixed precision integers: 32-bit or 64-bit integers and then ```Integer``` are arbitrary precision. If you use type **```Integer```** that will take a long time but it will **not overflow** like when you use ```Int```. Functions that take their arguments one by one are called **curried functions**. The person that invented this way of dealing with functions was Haskell B. Curry and Haskell is named after him. Functions with **more than two arguments** can be curried by returning nested functions. For application the parentheses associate to the left, for the function arrow they associate to the right, and that matches up perfectly (So in practice we don't have to write any parentheses). Polymorphic Function * [Theorems for free!](https://people.mpi-sws.org/~dreyer/tor/papers/wadler.pdf) * **Type variables** start with a **lower case** and **types** start with an **upper case**. ```length :: [a] -> Int``` * Overloaded when type of polymorphic function has one or more class constraints. ```sum :: Num a => [a] -> a``` ### Defining Functions * Sections An infix binary operator can be converted into a curried function written before its two arguments by using parentheses. ``` > 1 + 2 3 > (+) 1 2 3 > (+2) 1 3 > (1+) 2 3 ``` ### Higher-Order Function **Higher-order** if a function takes a function as an argument or returns a function as a result. **Common programming idioms** can be encoded as functions within the language itself. **Domain specific languages** can be defined as collections of higher-order functions. **Algebraic properties** of higher-order functions can be used to reason about programs. * The ```foldr``` function ``` foldr :: (a -> b -> b) -> b -> [a] -> b foldr f v [] = v foldr f v (x : xs) = f x (foldr f v xs) ``` * Instances of ```foldr``` ``` sum [] = 0 sum (x : xs) = x + sum xs ``` ``` sum = foldr (+) 0 ``` ``` or [] = False or (x : xs) = x || or xs ``` ``` or = foldr (||) False ``` ``` plusplus ys [] = ys plusplus ys (x : xs) = (:) x (plusplus ys xs) ``` ``` plusplus ys = foldr (:) ys ``` ## [Learn You a Haskell for Great Good!](http://learnyouahaskell.com/chapters) - [HASKELL 趣學指南](https://learnyoua.haskell.sg/content/zh-tw/) - [Welcome to the GHC User’s Guide](https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/index.html#) ### Syntax in Functions ``` > :info + > 1 + 2 > (+) 1 2 > elem 'a' ['a', 'b'] > 'a' `elem` ['a', 'b'] ``` Note: * We can define functions to be automatically infix by naming them using only special characters. * Not only can we call funcitons as infix with backticks, we can also define them using backticks. #### Pattern Matching * When defining functions in Haskell, you can create separate function bodies for different patterns. * When making patterns, we should always include a catchall pattern (name that starts with lowercase letter instead of actual value) at the end. * Patterns that include the ```:``` character will match only against lists of length one or more. ``` > let f [x, y, _] = True > f [1, 2, 3] True ``` ``` > let f (x:y:_) = True > f [1, 2] True > f [1, 2, 3] True > f [1, 2, 3, 4] True ``` #### As-patterns ``` firstLetter :: String -> String firstLetter "" = "Empty string!" firstLetter all@(x:xs) = "The first letter of " ++ all ++ " is " ++ [x] ``` #### Guards, Guards! * A **guards** is indicated by a pipe character ```|```, followed by a Boolean expression, followed by the function body that will be used if that expression evaluates to ```True```. * ***Guards*** must be indented by at least one space (I like to indent them by four spaces so that the code is more readable.) * The last guard in a function is ```otherwise```, which catches everything. If all the guards in a function eveluate to ```False```, and we haven't provided an ```otherwise``` catchall guard, evaluation falls through to thr next pattern. #### Where?! * ```where``` binding makes our programs faster, since our values are calculated just once. * All the variable names are aligned in a single column. * The variables we define in the ```where``` section of a function are visible only to that function. ``` bmiTell :: (RealFloat a) => a -> a -> String bmiTell weight height | bmi <= skinny = "You're underweight, you emo, you!" | bmi <= normal = "You're supposedly normal. Pffft, I bet you're ugly!" | bmi <= fat = "You're fat! Lose some weight, fatty!" | otherwise = "You're a whale, congratulations!" where bmi = weight / height ^ 2 skinny = 18.5 normal = 25.0 fat = 30.0 ``` #### Pattern Matching with where ``` initials :: String -> String -> String initials firstname lastname = [f] ++ ". " ++ [l] ++ "." where (f:_) = firstname (l:_) = lastname ``` #### Let It Be * ```let``` expressions allow you to bind to variables anywhere and are expressions themselves. * ```let``` are visible within the entire ```let``` expression. ``` let <bindings> in <expression> ``` ``` ghci> (let a = 100; b = 200; c = 300 in a*b*c, let foo="Hey "; bar = "there!" in foo ++ bar) (6000000,"Hey there!") ``` #### Pattern Matching with let ``` ghci> (let (a,b,c) = (1,2,3) in a+b+c) * 100 600 ``` #### let in List Comprehensions * The names defined in this ```let``` are visible to the output (the part before the ```|```) and everything in the list comprehension that comes after the ```let```. * If we use ```in``` in list comprehension, then only ```let``` expression knows the binding. ``` calcBmis :: (RealFloat a) => [(a, a)] -> [a] calcBmis xs = [bmi | (w, h) <- xs, let bmi = w / h ^ 2, bmi >= 25.0] ``` Note: ```(w, h) <- xs``` is called the **generator**. #### let in GHCi We omitted the ```in``` part in our first line, GHCi knows that we're not using ```zoot``` in that line, so it remembers for the rest of session. ``` ghci> let zoot x y z = x * y + z ghci> zoot 3 9 2 29 ``` A ```let``` expression that doesn't leave out the ```in``` part is an experssion in itself and represent a value. ``` ghci> let boot x y z = x * y + z in boot 3 4 2 14 ghci> boot < interactive>:1:0: Not in scope: `boot' ``` #### case Expressions * ```case``` expressions are expressions, much like ```if else``` expressions and ```let``` expressions. * ```case``` expressions can be used anywhere. ``` case expression of pattern -> result pattern -> result pattern -> result ``` ``` describeList :: [a] -> String describeList xs = "The list is " ++ case xs of [] -> "empty." [x] -> "a singleton list." xs -> "a longer list." ``` ### Higher-Order Functions Haskell functions can take functions as parameters and return functions as return values. A function that does either of these things is called a **higher-order function**. * **Currying** is when you break down a function that takes multiple arguments into a series of functions that take part of the arguments. * If we call a function with too few parameters, we get back a **partially applied function**, which is a function that takes as many parameters as we left out. ``` multThree :: (Num a) => a -> a -> a -> a ``` equals ``` multThree :: (Num a) => a -> (a -> (a -> a)) ``` #### Sections Infix function can also be partially applied by using **sections**. Note: ```-4``` means negative four. Use ```(subtract 4)``` to subtract 4. #### Lambda * Lambdas are anonymous functions that we use when need a function only once. * Lambda are expressions. * We usually surround lambdas with parantheses. * You can pattern match in lambdas, the only difference is that you can't define several patterns for one parameter. #### I Fold You So * Folds allow you to reduce a data structure (like a list) to a single value. * A fold takes a binary function, a starting value (often called the accumulator), and a list to fold up. * The fold function calls the given binary function, using the accumulator and the first (or last) element of the list as parameters. The resulting value is the new accumulator. This repeats until the function has traversed the entire list and reduce it down to a single accumulator. * ```foldl1``` and ```foldr1``` can not work on empty list, but ```foldl``` and ```foldr``` can. #### Left Folds with foldl ``` map' :: (a -> b) -> [a] -> [b] map' f xs = foldl (\acc x -> acc ++ [f x]) [] xs ``` #### Right Folds with foldr ``` map' :: (a -> b) -> [a] -> [b] map' f xs = foldr (\x acc -> f x : acc) [] xs ``` Note: ```++``` is much slower than ```:```. #### The foldl1 and foldr1 Functions They assume the first (or last) element of the list to be the starting accumulator, and then start the fold with the element next to it. ``` > let maximum' = foldr1 (\x acc -> if x > acc then x else acc) > maximum' [2] 2 > maximum' [2, 1] 2 ``` ``` > let last' = foldl1 (\_ x -> x) > last' [2] 2 > last' [2, 1] 1 ``` #### Another Way to Look at Folds Given ```[3, 4, 5, 6]``` and accumulator ```z```. * Right fold ``` f 3 (f 4 (f 5 (f 6 z))) ``` * Left fold ``` g (g (g (g z 3) 4) 5) 6 ``` #### Folding Infinite Lists * Right folds work on infinite list, whereas left folds do not. * ```foldr``` will work on infinite lists when the binary function that we are passing to it does not always need to evaluate its second parameter to give us some sort of answer. #### Scans The ```scanl``` and ```scanr``` functions are like ```foldl``` and ```foldr```, except they report all the intermediate accumulator states in the form of a list. ``` ghci> scanl (+) 0 [3,5,2,1] [0,3,8,10,11] ghci> scanr (+) 0 [3,5,2,1] [11,8,3,1,0] ``` #### Functions Application with $ * ```$``` function is called **function application operator**. * You can imagine```$``` as almost being the equivalent of writing an opening parenthesis and then writing a closing parenthesis on the far right side of the expression. * ```$``` has lowest precedence, whereas normal function application (putting a space between two things) has a really high precedence. ``` ($) :: (a -> b) -> a -> b f $ x = f x ``` ``` f a b c = ((f a) b) c ``` ``` f $ g $ x = f $ (g $ x) ``` #### Function Composition ``` (.) :: (b -> c) -> (a -> b) -> a -> c f . g = \x -> f (g x) ``` * Function composition is right-associative ``` (f . g . z) x = f (g (z x)) ``` ### Build Our Own Type and Type Class ``` > :t fromIntegral fromIntegral :: (Num b, Integral a) => a -> b ``` #### Algebraic data types intro * Value constructors are actually functions that ultimately return a value of a data type. ``` data Shape = Circle Float Float Float | Rectangle Float Float Float Float deriving (Show) ghci> :t Circle Circle :: Float -> Float -> Float -> Shape ghci> :t Rectangle Rectangle :: Float -> Float -> Float -> Float -> Shape ``` * Pattern match against value constructors (```[]```, ```False```, and ```5```, but those values did not have any fields). #### Type parameters * It's a very strong convention in Haskell to never add typeclass constraints in data declarations. #### Derived Instances * **Type class** is a sort of an interface that defines some behavior. * A **type** can be made an instance of a type class if it supports that behavior. #### Type Synonyms * Type synonyms are just about giving some types different names. ``` type String = [Char] ``` * Type synonyms can be used only in the type portion of Haskell. * Type declarations * Data declarations * Type annotations #### Recursive Data Structures * Infix value constructors must begin with a colon ``` infixr 5 :-: data List a = Empty | a :-: (List a) deriving (Show, Eq, Ord, Read) ``` #### Type Classes 102 ``` class Eq a where (==) :: a -> a -> Bool (/=) :: a -> a -> Bool x == y = not (x /= y) x /= y = not (x == y) ``` * ```a``` is type variable that will be made an instance of ```Eq``` . * Type variable must be lowercase. * Only require type declaration of those **behaviors (functions)** in type class definition (function bodies is optional). ``` instance (Eq m) => Eq (Maybe m) where Just x == Just y = x == y Nothing == Nothing = True _ == _ = False ``` * By specifying a type parameter as a type variable (```m```, which is in lowercase), we said that we want all types that are in the form of ```Maybe m```, where ```m``` is any type, to be an instance of ```Eq```. #### The Functor Type Class ``` class Functor f where fmap :: (a -> b) -> f a -> f b ``` * ```f``` must be a type constructor that takes only a parameter. * The type variable of ```Functor``` is kind of ```* -> *```. #### Kinds and some Type-Foo ``` > :k Int Int :: * ``` * A kind is the label of a type; while a type is the label of a value. * ```*``` indicates that the type is a concrete type. ### Input and Output ``` ghc --make test.hs ./test ``` * An I/O action is something that, when performed, will carry out an action with a side effect. * I/O actions are performed only when they fall into ```main```or we try to evaluate them at GHCi prompt. * When we punch in a number or call a function in GHCi and press ```ENTER```, GHCi will apply ```show``` to the resulting value, and then it will print it to the terminal by using ```putStrLn```. (GHCi actually uses ```print``` on that value to display it on the terminal.) ``` print :: (Show a) => a -> IO () print x = putStrLn (show x) ``` * When we evaluate an I/O action in GHCi, that action is performed, and then its result is printed out, unless that result is ```()```. ``` > :t getLine getLine :: IO String > getLine abc "abc" > :t print print :: (Show a) => a -> IO () > print "abc" "abc" > :t return () return () :: Monad m => m () > return () > :t return 5 return 5 :: (Monad m, Num a) => m a > return 5 5 ``` * Run ```main``` without printing out I/O action result. ``` runhaskell test.hs ``` #### Hello, World! ``` main = do putStrLn "Hello" name <- getLine putStrLn ("Hello " ++ name) ``` * To get the value out of an I/O action, you must perform it inside another I/O action by binding it to a name with ```<-```. * ```getLine``` is an I/O action that yields a String, so ```name``` has a type of String. * In a ```do``` block, except for the last line, every line in a ```do``` block that doesn't bind can be written with a bind ```->```. * The action that we got has a type of ```IO ()```, as that's the type of the last I/O action. ``` > :t putStrLn putStrLn :: String -> IO () > :t getLine getLine :: IO String > :t main main :: IO () ``` * The ```do``` block automatically extracts the value from the last action and yields that as its own result. ``` main = do return 1 putStrLn "b" putStrLn "c" return 2 ``` ``` > :t main main :: IO Integer ``` ``` > main b c 2 ``` ### Applicative Functors We don't need to think about types belonging to a big hierarchy , we can also introduce a new type class and then make already existing types instances of it. ``` class Functor f where fmap :: (a -> b) -> f a -> f b ``` ``` instance Functor [] where fmap = map ``` #### Functors Redux ``` instance Functor Maybe where fmap f (Just x) = Just (f x) fmap f Nothing = Nothing ``` ``` instance Functor Tree where fmap f EmptyTree = EmptyTree fmap f (Node x leftsub rightsub) = Node (f x) (fmap f leftsub) (fmap f rightsub) ``` ``` instance Functor (Either a) where fmap f (Right x) = Right (f x) fmap f (Left x) = Left x ``` #### I/O Actions As Functors ``` instance Functor IO where fmap f action = do result <- action return (f result) ``` #### Functions As Functors ``` instance Functor ((->) r) where fmap f g = (\x -> f (g x)) ``` ``` fmap :: (a -> b) -> (r -> a) -> (r -> b) ``` ``` instance Functor ((->) r) where fmap = (.) ``` #### Functor Law * All instances of ```Functor``` should abide by these two laws. * They are not enforced by Haskell automatically, so you need to test them youself when you make a functor. * Even though it's part of the ```Functor``` type class, it dosen't obey this functor law and is therefore not a functor. * Law 1 ``` fmap id = id ``` * Law 2 ``` fmap (f . g) = fmap f . fmap g ``` #### Using Applicative Functors ``` class (Functor f) => Applicative f where pure :: a -> f a (<*>) :: f (a -> b) -> f a -> f b ``` Note: ```<*>``` is left associative. #### The Applicative Style ``` (<$>) :: (Functor f) => (a -> b) -> f a -> f b f <$> x = fmap f x ``` ``` liftA2 :: (Applicative f) => (a -> b -> c) -> f a -> f b -> f c liftA2 f a b = f <$> a <*> b ``` #### Maybe the Applicative Functor ``` instance Applicative Maybe where pure = Just Noting <*> _ = Nothing (Just f) <*> something = fmap f something ``` #### Lists ``` instance Applicative [] where pure x = [x] fs <*> xs = [f x | f <- fs, x <- xs] ``` #### IO is Applicative Functor, too ``` instance Applicative IO where pure = return a <*> b = do f <- a x <- b return (f x) ``` #### Functions as Applicatives ``` instance Applicative ((->) r) where pure x = (\_ -> x) f <*> g = \x -> f x (g x) ``` #### Zip Lists ``` instance Applicative ZipList where pure x = ZipList (repeat x) ZipList fs <*> ZipList xs = ZipList (zipWith (\f x -> f x) fs xs) ``` Note: ```ZipList a``` type does not have a ```Show``` instance, so we need to use the ```getZipList``` function to extract a raw list from a zip list. #### Applicative Laws * Identity ```pure id <*> v = v``` * Composition ```pure (.) <*> u <*> v <*> w = u <*> (v <*> w)``` * Homomorphism ```pure f <*> pure x = pure (f x)``` * Interchange ```u <*> pure y = pure ($ y) <*> u``` * As a consequence of these laws, the ```Functor``` instance for ```f``` will satisfy. ```fmap f x = pure f <*> x``` ### Monoids #### types vs. newtype vs. data * If you just want your type signatures to look cleaner and be more descriptive, you probably want ```type``` synonyms. * If you want to take an existing type and wrap it in a new type in order to make it an instance of a type class, chances are you're looking for a ```newtype```. ``` newtype Pair b a = Pair {getPair :: (a, b)} ``` ``` instance Functor (Pair c) where fmap f (Pair (x, y)) = Pair (f x, y) ``` * If you want to make something completely new, odds are good that you're looking for the ```data``` keyword. #### Wrapping an Existing Type into a New Type In practice, you can think of ```newtype``` declarations as ```data``` declarations that can have only one value constructor and one field. ``` newtype ZipList a = ZipList { getZipList :: [a] } ``` ``` > :t ZipList ZipList :: [a] -> ZipList a > :t getZipList getZipList :: ZipList a -> [a] ``` Note: 1. ``data`` is slower than ```newtype``` due to overhead to all that wrapping and unwrapping type inside it. 2. Pattern matching on ```newtype``` values isn't like taking something out of a box (as it is with ```data```), but more about making a direct conversion from one type to another. 3. If we derive the instance for a type class, the type that we're wrapping must already be in that type class. #### The Monoid Type Class A monoid is made up of an associative binary function and a value that acts as an identity with respect to that function. Note: Associative means the order that we apply the binary function to the values does not matter. ``` class Monoid m where mempty :: m mappend :: m -> m -> m mconcat :: [m] -> m mconcat = foldr mappend mempty ``` #### The Monoid Laws * ```mempty `mappend` x = x``` * ```x `mappend` mempty = x``` * ```(x `mappend` y) `mappend` z = x `mappend` (y `mappend` z)``` ### Meet Some Monoids #### Lists are Monoids ``` instance Monoid [a] where mempty = [] mappend = (++) ``` #### Product and Sum ``` newtype Product a = Product { getProduct :: a } deriving (Eq, Ord, Read, Show, Bounded) ``` ``` instance Num a => Monoid (Product a) where mempty = Product 1 Product x `mappend` Product y = Product (x * y) ``` #### Any and All ``` newtype Any = Any { getAny :: Bool } deriving (Eq, Ord, Read, Show, Bounded) ``` ``` instance Monoid Any where mempty = Any False Any x `mappend` Any y = Any (x || y) ``` ``` newtype All = All { getAll :: Bool } deriving (Eq, Ord, Read, Show, Bounded) ``` ``` instance Monoid All where mempty = All True All x `mappend` All y = All (x && y) ``` #### The Ordering Monoid ``` instance Monoid Ordering where mempty = EQ LT `mappend` _ = LT EQ `mappend` y = y GT `mappend` _ = GT ``` #### Maybe the Monoid ``` instance Monoid a => Monoid (Maybe a) where mempty = Nothing Nothing `mappend` m = m m `mappend` Nothing = m Just m1 `mappend` Just m2 = Just (m1 `mappend` m2) ``` ``` newtype First a = First { getFirst :: Maybe a } deriving (Eq, Ord, Read, Show) ``` ``` instance Monoid (First a) where mempty = First Nothing First (Just x) `mappend` _ = First (Just x) First Nothing `mappend` x = x ``` #### Folding with Monoids * **Foldable** is for things that can be folded up. ``` ghci> import qualified Data.Foldable as F ghci> :t foldr foldr :: (a -> b -> b) -> b -> [a] -> b ghci> :t F.foldr F.foldr :: (F.Foldable t) => (a -> b -> b) -> b -> t a -> b ghci> :t F.foldl F.foldl :: (F.Foldable t) => (b -> a -> b) -> b -> t a -> b ``` * Implementing ```foldMap``` is all it takes for our type to be an instance of ```Foldable``` (we get ```foldr``` and ```foldl``` for free). ``` class Foldable t where foldMap :: Monoid m => (a -> m) -> t a -> m ``` ``` instance F.Foldable Tree where foldMap f Empty = mempty foldMap f (Node x l r) = F.foldMap f l `mappend` f x `mappend` F.foldMap f r ``` ``` testTree = Node 5 (Node 3 (Node 1 Empty Empty) (Node 6 Empty Empty) ) (Node 9 (Node 8 Empty Empty) (Node 10 Empty Empty) ) ``` ``` ghci> F.foldl (+) 0 testTree 42 ghci> F.foldl (*) 1 testTree 64800 ``` ``` ghci> F.foldMap (\x -> [x]) testTree [1,3,6,5,8,9,10] ``` ### A Fistful of Monads #### Upgrading Our Applicative Functors Monads are just applicative functors that support ```>>=```. (The ```>>=``` function is called **bind**) #### The Monad Type Class ``` class Applicative m => Monad m where return :: a -> m a (>>=) :: m a -> (a -> m b) -> m b (>>) :: m a -> m b -> m b x >> y = x >>= \_ -> y fail :: String -> m a fail msg = error msg ``` #### do Notation * Gruing together monadic values in sequence. * ```do``` expressions are just different syntax for chaining monadic values. ``` instance Monad Maybe where return x = Just x Nothing >>= f = Nothing Just x >>= f = f x fail _ = Nothing ``` ``` Just 3 >>= (\x -> Just "!" >>= (\y -> Just (show x ++ y))) ``` ``` foo :: Maybe String foo = do x <- Just 3 y <- Just "!" Just (show x ++ y) ``` Note: If any of the values that we try to extract from are ```Nothing```, the whole ```do``` expression will result in a ```Nothing```. ``` routine :: Maybe Pole routine = do start <- return (0,0) first <- landLeft 2 start Nothing second <- landRight 2 first landLeft 1 second ``` Note: Above ```Nothing``` is equivalent form of ```_ <- Nothing```. #### Pattern Matching and Failure When pattern matching fails in a ```do``` expression, the ```fail``` function (part of the ```monad``` type class) enables it to result in a failure in the context of the current monad, instead of making the program crash. #### The List Monad ``` instance Monad [] where return x = [x] xs >>= f = concat (map f xs) fail _ = [] ``` ``` ghci> [] >>= \x -> ["bad","mad","rad"] [] ghci> [1,2,3] >>= \x -> [] [] ``` ``` ghci> [1,2] >>= \n -> ['a','b'] >>= \ch -> return (n,ch) [(1,'a'),(1,'b'),(2,'a'),(2,'b')] ``` ``` listOfTuples :: [(Int,Char)] listOfTuples = do n <- [1,2] ch <- ['a','b'] return (n,ch) ``` In fact, list comprehensions are just syntatic sugar for using lists as monads. ``` ghci> [ (n,ch) | n <- [1,2], ch <- ['a','b'] ] [(1,'a'),(1,'b'),(2,'a'),(2,'b')] ``` #### MonadPlus and the guard Function ``` class Monad m => MonadPlus m where mzero :: m a mplus :: m a -> m a -> m a ``` ``` instance MonadPlus [] where mzero = [] mplus = (++) ``` ``` guard :: (MonadPlus m) => Bool -> m () guard True = return () guard False = mzero ``` ``` ghci> [1..50] >>= (\x -> guard ('7' `elem` show x) >> return x) [7,17,27,37,47] ``` ``` ghci> guard (5 > 2) >> return "cool" :: [String] ["cool"] ghci> guard (1 > 2) >> return "cool" :: [String] [] ``` #### A Knight's Quest ``` type KnightPos = (Int,Int) ``` ``` moveKnight :: KnightPos -> [KnightPos] moveKnight (c,r) = do (c',r') <- [(c+2,r-1),(c+2,r+1),(c-2,r-1),(c-2,r+1) ,(c+1,r-2),(c+1,r+2),(c-1,r-2),(c-1,r+2) ] guard (c' `elem` [1..8] && r' `elem` [1..8]) return (c',r') ``` ``` ghci> moveKnight (6,2) [(8,1),(8,3),(4,1),(4,3),(7,4),(5,4)] ghci> moveKnight (8,1) [(6,2),(7,3)] ``` ``` in3 :: KnightPos -> [KnightPos] in3 start = do first <- moveKnight start second <- moveKnight first moveKnight second ``` ``` in3 start = return start >>= moveKnight >>= moveKnight >>= moveKnight ``` ``` canReachIn3 :: KnightPos -> KnightPos -> Bool canReachIn3 start end = end `elem` in3 start ``` ``` ghci> (6,2) `canReachIn3` (6,1) True ghci> (6,2) `canReachIn3` (7,3) False ``` ``` import Data.List inMany :: Int -> KnightPos -> [KnightPos] inMany x start = return start >>= foldr (<=<) return (replicate x moveKnight) ``` ``` canReachIn :: Int -> KnightPos -> KnightPos -> Bool canReachIn x start end = end `elem` inMany x start ``` #### Monand Laws #### Left Identity ```return x >>= f = f x``` #### Right Identity ```m >>= return = m``` #### Associativity ```(m >>= f) >>= g = m >>= (\x -> f x >>= g)``` ``` (.) :: (b -> c) -> (a -> b) -> (a -> c) f . g = (\x -> f (g x)) ``` ``` (<=<) :: (Monad m) => (b -> m c) -> (a -> m b) -> (a -> m c) f <=< g = (\x -> g x >>= f) ``` ``` f <=< (g <=< h) = (f <=< g) <=< h ``` ### For a Few Monads More * The ```mtl``` package comes with Haskell-Platform (a **package** is a collection of modules), check by **ghc-pkg list**. #### The Writer Type * The ```Writer``` monad is for values that have another value attached that acts as a sort of log value. * ```Writer``` allows us to do computations while making sure that all the log values are combined into one log value, which then is attached to the result. ``` newtype Writer w a = Writer { runWriter :: (a, w)} ``` ``` instance (Monoid w) => Monad (Writer w) where return x = Writer (x, mempty) (Writer (x, v)) >>= f = let (Writer (y, v')) = f x in Writer (y, v `mappend` v') ``` ``` import Control.Monad.Writer ``` Note: The ```Writer``` instance doesn't feature an implementation for ```fail```, so if a pattern match fails in ```do``` notation, ``error`` is called. * In this case, all the monoid values that come attached are ``mappended``, and so are reflected in the final result. ``` multWithLog :: Writer [String] Int multWithLog = do a <- logNumber 3 b <- logNumber 5 tell ["Gonna multiply these two"] return (a*b) ``` ``` ghci> runWriter multWithLog (15,["Got number: 3","Got number: 5","Gonna multiply these two"]) ``` ``` > :t tell ["hello"] tell ["hello"] :: MonadWriter [[Char] m => m () ``` Note: ```MonadWriter``` is a type class. #### Inefficient List Construction A list is a data structure that's constructed from left to right. * Fast ver. ``` a ++ (b ++ (c ++ (d ++ (e ++ f)))) ``` * Slow ver. (Everytime it wants to add the right part to the left part, it must construct the left part all the way from the begnning!) ``` ((((a ++ b) ++ c) ++ d) ++ e) ++ f ``` #### Using Difference Lists A difference list is actually a function that takes a list and prepends another list to it. ``` newtype DiffList a = DiffList { getDiffList :: [a] -> [a] } ``` ``` instance Monoid (DiffList a) where mempty = DiffList (\xs -> [] ++ xs) (DiffList f) `mappend` (DiffList g) = DiffList (\xs -> f (g xs)) ``` ``` toDiffList :: [a] -> DiffList a toDiffList xs = DiffList (xs++) fromDiffList :: DiffList a -> [a] fromDiffList (DiffList f) = f [] ``` #### Comparing Performance ``` finalCountDown :: Int -> Writer (DiffList String) () finalCountDown 0 = do tell (toDiffList ["0"]) finalCountDown x = do finalCountDown (x-1) tell (toDiffList [show x]) ``` ``` ghci> mapM_ putStrLn . snd . runWriter $ finalCountDown 500000 ``` #### Functions as Monads ``` import Control.Monad.Instances ``` ``` instance Monad ((->) r) where return x = \_ -> x h >>= f = \w -> f (h w) w ``` #### The Reader Monad The function monad is also called the reader monad. ``` import Control.Monad.Instances addStuff :: Int -> Int addStuff = do a <- (*2) b <- (+10) return (a+b) ``` ``` ghci> addStuff 3 19 ``` #### Stateful Computations Assignment in most other languages could be thought of as a stateful computation. #### The State Monad ``` import Control.Monad.State ``` ``` newtype State s a = State { runState :: s -> (a,s) } ``` ``` instance Monad (State s) where return x = State $ \s -> (x,s) (State h) >>= f = State $ \s -> let (a, newState) = h s (State g) = f a in g newState ``` ``` import Control.Monad.State pop :: State Stack Int pop = State $ \(x:xs) -> (x,xs) push :: Int -> State Stack () push a = State $ \xs -> ((),a:xs) ``` ``` stackStuff :: State Stack () stackStuff = do a <- pop if a == 5 then push 5 else do push 3 push 8 ``` ``` ghci> runState stackStuff [9,0,2,1,0] ((),[8,3,0,2,1,0]) ``` #### Getting and Setting State ```MonadState``` is a type class. ``` class Monad m => MonadState s m | m -> s where ``` Minimal definition is either both of `get` and `put` or just `state` ``` > :t get get :: MonadState s m => m s > :t put put :: MonadState s m => s -> m () > :t state state :: MonadState s m => (s -> (a, s)) -> m a ``` ``` get = state $ \s -> (s,s) ``` ``` put newState = state $ \s -> ((),newState) ``` ``` stackyStack :: State Stack () stackyStack = do stackNow <- get if stackNow == [1,2,3] then put [8,3,1] else put [9,2,1] ``` #### Error Error On the Wall ``` import Data.Either ``` ``` instance Monad (Either e) where return x = Right x Left l >>= _ = Left l Right r >>= k = k r ``` #### Some Useful Monadic Functions #### liftM and Friends ``` fmap :: (Functor f) => (a -> b) -> f a -> f b ``` ``` liftM :: (Monad m) => (a -> b) -> m a -> m b liftM f m = m >>= (\x -> return (f x)) ``` ``` liftM :: (Monad m) => (a -> b) -> m a -> m b liftM f m = do x <- m return (f x) ``` ``` (<*>) :: (Applicative f) => f (a -> b) -> f a -> f b ``` ``` ap :: (Monad m) => m (a -> b) -> m a -> m b ap mf m = do f <- mf x <- m return (f x) ``` ``` liftM2 :: (Monad m) => (a -> b -> c) -> m a -> m b -> m c liftM2 f x y = f <$> x <*> y ``` #### The join Function ``` join :: (Monad m) => m (m a) -> m a join mm = do m <- mm m ``` ``` ghci> join (Right (Right 9)) :: Either String Int Right 9 ghci> join (Right (Left "error")) :: Either String Int Left "error" ghci> join (Left "error") :: Either String Int Left "error" `````` * To flatten a ```Writer``` value whose result is a ```Writer``` value itself, we need to ```mappend``` the monoid value. ``` ghci> runWriter $ join (Writer (Writer (1,"aaa"),"bbb")) (1,"bbbaaa") ``` ``` ghci> runState (join (State $ \s -> (push 10,1:2:s))) [0,0,0] ((),[10,1,2,0,0,0]) ``` * If we're making our own ```Monad``` instance for some type. This is because it's often easier to figure out how we would flatten a nested monadic value than to figure out how to implement ```>>=```. ``` m >>= f = join (fmap f m) ``` ``` Just 9 >>= (\x -> Just (x+1)) = Just 10 join (fmap (\x -> Just (x+1)) Just 9) = Just 10 ``` #### filterM ``` filter :: (a -> Bool) -> [a] -> [a] ``` ``` filterM :: (Monad m) => (a -> m Bool) -> [a] -> m [a] ``` ``` keepSmall :: Int -> Writer [String] Bool keepSmall x | x < 4 = do tell ["Keeping " ++ show x] return True | otherwise = do tell [show x ++ " is too large, throwing it away"] return False ``` ``` ghci> mapM_ putStrLn $ snd $ runWriter $ filterM keepSmall [9,1,5,2,10,3] 9 is too large, throwing it away Keeping 1 5 is too large, throwing it away Keeping 2 10 is too large, throwing it away Keeping 3 ``` ``` powerset :: [a] -> [[a]] powerset xs = filterM (\x -> [True, False]) xs ``` ``` ghci> powerset [1,2,3] [[1,2,3],[1,2],[1,3],[1],[2,3],[2],[3],[]] ``` #### foldM ``` foldl :: (a -> b -> a) -> a -> [b] -> a ``` ``` foldM :: (Monad m) => (a -> b -> m a) -> a -> [b] -> m a ``` ``` binSmalls :: Int -> Int -> Maybe Int binSmalls acc x | x > 9 = Nothing | otherwise = Just (acc + x) ``` ``` ghci> foldM binSmalls 0 [2,8,3,1] Just 14 ghci> foldM binSmalls 0 [2,11,3,1] Nothing ``` #### Composing Monadic Functions ``` ghci> let g = (\x -> return (x+1)) <=< (\x -> return (x*100)) ghci> Just 4 >>= g Just 401 ``` ``` ghci> let f = foldr (.) id [(+1),(*100),(+3)] ghci> f 1 401 ```