. many <$> operators >>=, many $ without <*> names !!Constructors and record accessors become terms
Control flow
Bool, Int, [a], Maybe adata or newtypetypedata 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 in-line
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 ghc-prim ... linking ... done.
Loading package integer-gmp ... 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 = ghc-prim:GHC.Types.I#
  ghc-prim:GHC.Prim.Int#
  -- Defined in `ghc-prim: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 built-in 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) badd :: 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:1-24: Non-exhaustive 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  | 
|