.
many <$>
operators >>=
, many $
without <*>
names !!
Constructors and record accessors become terms
Control flow
Bool
, Int
, [a]
, Maybe a
data
or newtype
type
data Bool = True  False
data Ordering = LT  EQ  GT
data Choice = Definitely  Possibly  NoWay
data Int = …  1  0  1  2  …
data Char = …  'a'  'b'  …
3 * 3 == 9
possible inhabitantsdata CoinFlip = CoinFlip Bool
data Choices = Choices Choice Choice
data Coord = Coord { x :: Double, y :: Double }
(1 * 2) + 1
possibilitiesdata Possibly = Certainly Bool
 Uncertain
data DrawCommand = Point Int Int
 Line Int Int Int Int
 Rect Int Int Int Int
data IntTree = Node Int IntTree IntTree
 Leaf
type
creates aliases (can help readability)data List a = Cons a (List a)
 Nil
data Maybe a = Just a
 Nothing
type IntList = List Int
type MaybeBool = Maybe Bool
type String = [Char]
type Unit = ()
type ListOfInt = [Int]
type ListOfInt = [] Int
type AddFun = Int > Int > Int
type AddFun = Int > (Int > Int)
type AddFun = (>) Int ((>) Int Int)
type IntTuple = (Int, Int)
type IntTuple = (,) Int Int
data Choice = Definitely
 Possibly
 NoWay
data Choices = Choices Choice Choice
mkChoices :: Choice > Choice > Choices
mkChoices a b = Choices a b
fstChoice :: Choices > Choice
fstChoice (Choices a _) = a
data Choice = Definitely
 Possibly
 NoWay
data Choices = Choices Choice Choice
mkChoices :: Choice > Choice > Choices
mkChoices a b = Choices a b
fstChoice :: Choices > Choice
fstChoice (Choices a _) = a
 Terms can be annotated inline
2 ^ (1 :: Int)
 Bindings can be annotated
success :: a > Maybe a
 Constructors are terms
 (and product constructors are functions)
success x = Just x
 Constructors can be pattern matched
 _ is a wildcard
case success True of
Just True > ()
_ > ()
$ runhaskell help
Usage: runghc [runghc flags] [GHC flags] module [program args]
The runghc flags are
f /path/to/ghc Tell runghc where GHC is
help Print this usage information
version Print version number
$ ghci
GHCi, version 7.8.2: http://www.haskell.org/ghc/ :? for help
Loading package ghcprim ... linking ... done.
Loading package integergmp ... linking ... done.
Loading package base ... linking ... done.
h>
:t
shows type information
h> :t map
map :: (a > b) > [a] > [b]
h> :t map (+1)
map (+1) :: Num b => [b] > [b]
h> :t (>>=)
(>>=) :: Monad m => m a > (a > m b) > m b
:i
shows typeclass info
h> :i Num
class Num a where
(+) :: a > a > a
(*) :: a > a > a
() :: a > a > a
negate :: a > a
abs :: a > a
signum :: a > a
fromInteger :: Integer > a
 Defined in `GHC.Num'
instance Num Integer  Defined in `GHC.Num'
instance Num Int  Defined in `GHC.Num'
instance Num Float  Defined in `GHC.Float'
instance Num Double  Defined in `GHC.Float'
:i
shows term info
h> :info map
map :: (a > b) > [a] > [b]
 Defined in `GHC.Base'
h> :info (>>=)
class Monad m where
(>>=) :: m a > (a > m b) > m b
...
 Defined in `GHC.Base'
infixl 1 >>=
:i
shows type info
h> :info Int
data Int = ghcprim:GHC.Types.I#
ghcprim:GHC.Prim.Int#
 Defined in `ghcprim:GHC.Types'
instance Bounded Int  Defined in `GHC.Enum'
instance Enum Int  Defined in `GHC.Enum'
instance Eq Int  Defined in `GHC.Classes'
instance Integral Int  Defined in `GHC.Real'
instance Num Int  Defined in `GHC.Num'
instance Ord Int  Defined in `GHC.Classes'
instance Read Int  Defined in `GHC.Read'
instance Real Int  Defined in `GHC.Real'
instance Show Int  Defined in `GHC.Show'
:l
load a module
:r
to reload
h> :! echo 'hello = print "hello"' > Hello.hs
h> :l Hello
[1 of 1] Compiling Main ( Hello.hs, interpreted )
Ok, modules loaded: Main.
h> hello
"hello"
h> :! echo 'hello = print "HELLO"' > Hello.hs
h> :r
[1 of 1] Compiling Main ( Hello.hs, interpreted )
Ok, modules loaded: Main.
h> hello
"HELLO"
map :: (a > b) > [a] > [b]
map _ [] = []
map f (x:xs) = f x : map f xs
foldr :: (a > b > b) > b > [a] > b
foldr k z = go
where
go [] = z
go (y:ys) = y `k` go ys
isJust :: Maybe a > Bool
isJust (Just _) = True
isJust Nothing = False
Haskell only implements linear patterns
 DOES NOT WORK!
isEqual :: a > a > Bool
isEqual a a = True
isEqual _ _ = False
This isn't even possible! Only constructors can be pattern matched. Types have no builtin equality.
 Symbolic operators can be used
 prefix when in (parentheses)
(+) a b
 Named functions can be used
 infix when in `backticks`
x `elem` xs
 infixl, infixr define associativity
 and precedence (0 lowest, 9 highest)
infixr 5 `append`
a `append` b = a ++ b
add :: Integer > Integer > Integer
add acc x = acc + x
sumFun :: [Integer] > Integer
sumFun xs = foldl add 0 xs
sumLambda :: [Integer] > Integer
sumLambda xs = foldl (\acc x > acc + x) 0 xs
a > b > c
is really a > (b > c)
f a b
is really (f a) b
add :: Integer > Integer > Integer
add acc x = acc + x
sumFun :: [Integer] > Integer
sumFun xs = foldl add 0 xs
sumLambda :: [Integer] > Integer
sumLambda xs = foldl (\acc x > acc + x) 0 xs
add :: Integer > Integer > Integer
add acc x = acc + x
sumFun :: [Integer] > Integer
sumFun = foldl add 0
sumLambda :: [Integer] > Integer
sumLambda = foldl (\acc x > acc + x) 0
add :: Integer > Integer > Integer
add acc x = (+) acc x
sumFun :: [Integer] > Integer
sumFun = foldl add 0
sumLambda :: [Integer] > Integer
sumLambda = foldl (\acc x > (+) acc x) 0
add :: Integer > Integer > Integer
add acc = (+) acc
sumFun :: [Integer] > Integer
sumFun = foldl add 0
sumLambda :: [Integer] > Integer
sumLambda = foldl (\acc > (+) acc) 0
add :: Integer > Integer > Integer
add = (+)
sumFun :: [Integer] > Integer
sumFun = foldl add 0
sumLambda :: [Integer] > Integer
sumLambda = foldl (+) 0
isNegative :: (Num a) => a > Bool
isNegative x
 x < 0 = True
 otherwise = False
absoluteValue :: (Num a) => a > Bool
absoluteValue x
 isNegative x = x
 otherwise = x
 (), pronounced "unit"
unit :: ()
unit = ()
 Char
someChar :: Char
someChar = 'x'
 Instances of Num typeclass
someDouble :: Double
someDouble = 1
 Instances of Fractional typeclass
someRatio :: Rational
someRatio = 1.2345
 [a], type can be written prefix as `[] a`
someList, someOtherList :: [Int]
someList = [1, 2, 3]
someOtherList = 4 : 5 : 6 : []
dontWriteThis = (:) 4 (5 : (:) 6 [])
 (a, b), can be written prefix as `(,) a b`
someTuple, someOtherTuple :: (Int, Char)
someTuple = (10, '4')
someOtherTuple = (,) 4 '2'
 [Char], also known as String
 (also see the OverloadedStrings extension)
someString :: String
someString = "foo"
class Equals a where
isEqual :: a > a > Bool
instance Equals Choice where
isEqual Definitely Definitely = True
isEqual Possibly Possibly = True
isEqual NoWay NoWay = True
isEqual _ _ = False
instance (Equals a) => Equals [a] where
isEqual (a:as) (b:bs) = isEqual a b &&
isEqual as bs
isEqual as bs = null as && null bs
{
class Eq a where
(==) :: a > a > Bool
}
instance Eq Choice where
Definitely == Definitely = True
Possibly == Possibly = True
NoWay == NoWay = True
_ == _ = False
data Choice = Definitely
 Possibly
 NoWay
deriving (Eq)
data Choice = Definitely
 Possibly
 NoWay
deriving ( Eq, Ord, Enum, Bounded
, Show, Read )
prop_intIdentity :: Int > Bool
prop_intIdentity i = i == i
$ ghci
λ> import Test.QuickCheck
λ> quickCheck (\i > (i :: Int) == i)
+++ OK, passed 100 tests.
λ> import Test.QuickCheck
λ> quickCheck (\i > (i :: Double) + 1 > i)
+++ OK, passed 100 tests.
λ> import Test.QuickCheck
λ> quickCheck (\i > (i :: Double) + 1 > i)
+++ OK, passed 100 tests.
λ> let i = 0/0 :: Double in i + 1 > i
False
λ> import Test.QuickCheck
λ> quickCheck (\i > (i :: Double) + 1 > i)
+++ OK, passed 100 tests.
λ> let i = 0/0 :: Double in i + 1 > i
False
λ> let i = 1e16 :: Double in i + 1 > i
False
main :: IO ()
main = do
secret < readFile "/etc/passwd"
writeFile "/tmp/passwd" secret
return ()
do m
 desugars to:
m
do a < m
return a
 desugars to:
m >>= \a > return a
do m
return ()
 desugars to:
m >> return ()
main :: IO ()
main = do
secret < readFile "/etc/passwd"
writeFile "/tmp/passwd" secret
return ()
main :: IO ()
main =
readFile "/etc/passwd" >>= \secret > do
writeFile "/tmp/passwd" secret
return ()
main :: IO ()
main =
readFile "/etc/passwd" >>= \secret >
writeFile "/tmp/passwd" secret >>
return ()
main :: IO ()
main =
readFile "/etc/passwd" >>= \secret >
writeFile "/tmp/passwd" secret
main :: IO ()
main =
readFile "/etc/passwd" >>=
writeFile "/tmp/passwd"
flatMap :: (a > [b]) > [a] > [b]
flatMap f xs = [ y  x < xs, y < f x ]
flatMap :: (a > [b]) > [a] > [b]
flatMap f xs = do
x < xs
y < f x
return y
flatMap :: (a > [b]) > [a] > [b]
flatMap f xs = do
x < xs
f x
flatMap :: (a > [b]) > [a] > [b]
flatMap f xs = xs >>= \x > f x
flatMap :: (a > [b]) > [a] > [b]
flatMap f xs = xs >>= f
flatMap :: (a > [b]) > [a] > [b]
flatMap f xs = flip (>>=) f xs
flatMap :: (a > [b]) > [a] > [b]
flatMap = flip (>>=)
flatMap :: (a > [b]) > [a] > [b]
flatMap = (=<<)
 WordCount1.hs
main :: IO ()
main = do
input < getContents
let wordCount = length (words input)
print wordCount
 WordCount2.hs
main :: IO ()
main =
getContents >>= \input >
let wordCount = length (words input)
in print wordCount
 WordCount3.hs
main :: IO ()
main = getContents >>= print . length . words
>>=
?do
is just syntax sugar for the >>=
(bind) operator.main
, the Haskell runtime will evaluate these actions Function composition
(.) :: (b > c) > (a > b) > a > c
f . g = \x > f (g x)
 Function application (with a lower precedence)
($) :: (a > b) > a > b
f $ x = f x
map f (map g xs) = map (f . g) xs
{# RULES
"ByteString specialise break (x==)" forall x.
break ((==) x) = breakByte x
"ByteString specialise break (==x)" forall x.
break (==x) = breakByte x
#}
{# RULES
"ByteString specialise break (x==)" forall x.
break ((==) x) = breakByte x
"ByteString specialise break (==x)" forall x.
break (==x) = breakByte x
#}
import Data.ByteString.Char8 (ByteString, break)
splitLine :: ByteString > (ByteString, ByteString)
splitLine = break (=='\n')
{# RULES
"ByteString specialise break (x==)" forall x.
break ((==) x) = breakByte x
"ByteString specialise break (==x)" forall x.
break (==x) = breakByte x
#}
import Data.ByteString.Char8 (ByteString, break)
splitLine :: ByteString > (ByteString, ByteString)
splitLine = breakByte '\n'
 [1..] is an infinite list, [1, 2, 3, ...]
print (head (map (*2) [1..]))
 [1..] is an infinite list, [1, 2, 3, ...]
print (head (map (*2) [1..]))
 Outside in, print x = putStrLn (show x)
putStrLn (show (head (map (*2) [1..]))
 Outside in, print x = putStrLn (show x)
putStrLn (show (head (map (*2) [1..]))
 head (x:_) = x
 map f (x:xs) = f x : map f xs
 desugar [1..] syntax
putStrLn (show (head (map (*2) (enumFrom 1))))
 desugar [1..] syntax
putStrLn (show (head (map (*2) (enumFrom 1))))
 enumFrom n = n : enumFrom (succ n)
putStrLn (show (head (map (*2)
(1 : enumFrom (succ 1)))))
 enumFrom n = n : enumFrom (succ n)
putStrLn (show (head (map (*2)
(1 : enumFrom (succ 1)))))
 apply map
putStrLn (show (head
((1*2) :
map (*2) (enumFrom (succ 1)))))
 apply map
putStrLn (show (head ((1*2) : …)))
 apply head
putStrLn (show (1*2))
 apply head
putStrLn (show (1*2))
 show pattern matches on its argument
putStrLn (show 2)
 show pattern matches on its argument
putStrLn (show 2)
 apply show
putStrLn "2"
if' :: Bool > a > a > a
if' cond a b = case cond of
True > a
False > b
(&&) :: Bool > Bool > Bool
a && b = case a of
True > b
False > False
const :: a > b > a
const x = \_ > x
fib :: [Integer]
fib = 0 : 1 : zipWith (+) fib (tail fib)
cycle :: [a] > [a]
cycle xs = xs ++ cycle xs
iterate :: (a > a) > a > [a]
iterate f x = x : iterate f (f x)
takeWhile :: (a > Bool) > [a] > [a]
takeWhile _ [] = []
takeWhile p (x:xs)
 p x = x : takeWhile p xs
 otherwise = []
h> let f x = head True
<interactive>:23:16:
Couldn't match expected type `[a0]' with actual type `Bool'
In the first argument of `head', namely `True'
In the expression: head True
In an equation for `f': f x = head True
h> let f x = heads True
<interactive>:24:11:
Not in scope: `heads'
Perhaps you meant one of these:
`reads' (imported from Prelude),
`head' (imported from Prelude)
h> let x = x in x
 Infinite recursion, not a fun case to deal with!
h> case False of True > ()
*** Exception: <interactive>:29:124: Nonexhaustive patterns …
h> head []
*** Exception: Prelude.head: empty list
h> error "this throws an exception"
*** Exception: this throws an exception
h> undefined
*** Exception: Prelude.undefined
 Polymorphic and recursive
data List a = Cons a (List a)
 Nil
deriving (Show)
data Tree a = Leaf a
 Branch (Tree a) (Tree a)
deriving (Show)
listMap :: (a > b) > List a > List b
listMap _ Nil = Nil
listMap f (Cons x xs) = Cons (f x) (listMap f xs)
treeToList :: Tree a > List a
treeToList root = go root Nil
where
 Note that `go` returns a function!
go (Leaf x) = Cons x
go (Branch l r) = go l . go r
module List where
data List a = Cons a (List a)
 Nil
instance (Eq a) => Eq (List a) where
(Cons a as) == (Cons b bs) = a == b && as == bs
Nil == Nil = True
_ == _ = False
instance Functor List where
fmap _ Nil = Nil
fmap f (Cons x xs) = Cons (f x) (fmap f xs)
{# LANGUAGE DeriveFunctor #}
module List where
data List a = Cons a (List a)
 Nil
deriving (Eq, Functor)
import Data.List (sort)
newtype Down a = Down { unDown :: a }
deriving (Eq)
instance (Ord a) => Ord (Down a) where
compare (Down a) (Down b) = case compare a b of
LT > GT
EQ > EQ
GT > LT
reverseSort :: Ord a => [a] > [a]
reverseSort = map unDown . sort . map Down
class Monoid a where
mempty :: a
mappend :: a > a > a
instance Monoid [a] where
mempty = []
mappend = (++)
infixr 6 <>
(<>) :: (Monoid a) => a > a > a
(<>) = mappend
class Functor f where
fmap :: (a > b) > f a > f b
instance Functor [] where
fmap = map
instance Functor Maybe where
fmap f (Just x) = Just (f x)
fmap _ Nothing = Nothing
infixl 4 <$>
(<$>) :: Functor f => (a > b) > f a > f b
(<$>) = fmap
class (Functor f) => Applicative f where
pure :: a > f a
infixl 4 <*>
(<*>) :: f (a > b) > f a > f b
instance Applicative [] where
pure x = [x]
fs <*> xs = concatMap (\f > map f xs) fs
instance Applicative Maybe where
pure = Just
Just f <*> Just x = Just (f x)
_ <*> _ = Nothing
class Monad m where
return :: a > m a
(>>=) :: m a > (a > m b) > m b
(>>) :: m a > m b > m b
ma >> mb = ma >>= \_ > mb
instance Monad [] where
return = pure
m >>= f = concatMap f m
instance Monad Maybe where
return = pure
Just x >>= f = f x
Nothing >>= _ = Nothing
{# LANGUAGE OverloadedStrings #}
module SJSON where
import Prelude hiding (concat)
import Data.Text (Text, concat)
import Data.Attoparsec.Text
import Control.Applicative
data JSON = JArray [JSON]
 JObject [(Text, JSON)]
 JText Text
deriving (Show)
pJSON :: Parser JSON
pJSON = choice [ pText, pObject, pArray ]
where
pString = concat <$> "\"" .*> many pStringChunk <*. "\""
pStringChunk = choice [ "\\\"" .*> pure "\""
, takeWhile1 (not . (`elem` "\\\""))
, "\\" ]
pText = JText <$> pString
pPair = (,) <$> pString <*. ":" <*> pJSON
pObject = JObject <$> "{" .*> (pPair `sepBy` ",") <*. "}"
pArray = JArray <$> "[" .*> (pJSON `sepBy` ",") <*. "]"
A monad is just a monoid in the category of endofunctors, what's the problem?
Terminology from category theory can be intimidating (at first)!
return
probably doesn't mean what you think it means.
sum :: Num a => [a] > a
sum [] = 0
sum (x:xs) = x + sum xs
sum :: Num [a] => [a] > a
sum = go 0
where
go acc (x:xs) = go (acc + x) (go xs)
go acc [] = acc
sum :: Num [a] => [a] > a
sum = go 0
where
go acc _
 acc `seq` False = undefined
go acc (x:xs) = go (acc + x) (go xs)
go acc [] = acc
{# LANGUAGE BangPatterns #}
sum :: Num [a] => [a] > a
sum = go 0
where
go !acc (x:xs) = go (acc + x) (go xs)
go acc [] = acc
Slides 

Source 

bob@redivi.com 
