Haskell Tour (Part 2)
-
Upload
william-taysom -
Category
Technology
-
view
2.416 -
download
3
description
Transcript of Haskell Tour (Part 2)
HaskellA Whirlwind Tour
(Part II)William Taysom ~ 2011
Haskell is a non-strict, purely functional programming language with strong,static type inference.
Review
Recursive Data
data Color = Red | Green | Blue | Mix Color Color
Recursive Functions
hue :: Color -> Doublehue Red = 0hue Green = 120hue Blue = 240
hue (Mix c c') = let h = hue c h' = hue c' m = average h h' m' = norm (m + 180) d = distance h m in case compare d 90 of LT -> m EQ -> nan GT -> m'
norm h | h < 360 = h | otherwise = norm (h - 360)
h = 300
h' = 60
m = 180
m' = 0
ParametricTypes
Tuple (Product)
data Point = Point Double Double
Tuple (Product)
data Pair a b = Pair a b
Tuple (Product)
data (a, b) = (a, b)-- Built-in syntax:-- definition only for illustrative purposes.
Tuple (Product)
data (a, b) = (a, b)-- Built-in syntax:-- definition only for illustrative purposes.
ghci> (Blue, False)
ghci> (Blue, False)(Blue,False)ghci>
ghci> (Blue, False)(Blue,False)ghci> (,) Blue False
ghci> (Blue, False)(Blue,False)ghci> (,) Blue False(Blue,False)ghci>
ghci> (Blue, False)(Blue,False)ghci> (,) Blue False(Blue,False)ghci> :t it
ghci> (Blue, False)(Blue,False)ghci> (,) Blue False(Blue,False)ghci> :t itit :: (Color, Bool)ghci>
ghci> (Blue, False)(Blue,False)ghci> (,) Blue False(Blue,False)ghci> :t itit :: (Color, Bool)ghci> :t (,)
ghci> (Blue, False)(Blue,False)ghci> (,) Blue False(Blue,False)ghci> :t itit :: (Color, Bool)ghci> :t (,)(,) :: a -> b -> (a, b)ghci>
ghci> (Blue, False)(Blue,False)ghci> (,) Blue False(Blue,False)ghci> :t itit :: (Color, Bool)ghci> :t (,)(,) :: a -> b -> (a, b)ghci> :kind (,)
ghci> (Blue, False)(Blue,False)ghci> (,) Blue False(Blue,False)ghci> :t itit :: (Color, Bool)ghci> :t (,)(,) :: a -> b -> (a, b)ghci> :kind (,)(,) :: * -> * -> *ghci>
ghci> (Blue, False)(Blue,False)ghci> (,) Blue False(Blue,False)ghci> :t itit :: (Color, Bool)ghci> :t (,)(,) :: a -> b -> (a, b)ghci> :kind (,)(,) :: * -> * -> *ghci> :k Color
ghci> (Blue, False)(Blue,False)ghci> (,) Blue False(Blue,False)ghci> :t itit :: (Color, Bool)ghci> :t (,)(,) :: a -> b -> (a, b)ghci> :kind (,)(,) :: * -> * -> *ghci> :k ColorColor :: *ghci>
Color :: *ghci>
Color :: *ghci> :t (Red, Blue, Green)
Color :: *ghci> :t (Red, Blue, Green)(Red, Blue, Green) :: (Color, Color, Color)ghci>
Color :: *ghci> :t (Red, Blue, Green)(Red, Blue, Green) :: (Color, Color, Color)ghci> :t (,,)
Color :: *ghci> :t (Red, Blue, Green)(Red, Blue, Green) :: (Color, Color, Color)ghci> :t (,,)(,,) :: a -> b -> c -> (a, b, c)ghci>
Color :: *ghci> :t (Red, Blue, Green)(Red, Blue, Green) :: (Color, Color, Color)ghci> :t (,,)(,,) :: a -> b -> c -> (a, b, c)ghci> :t (,,,)
Color :: *ghci> :t (Red, Blue, Green)(Red, Blue, Green) :: (Color, Color, Color)ghci> :t (,,)(,,) :: a -> b -> c -> (a, b, c)ghci> :t (,,,)(,,,) :: a -> b -> c -> d -> (a, b, c, d)ghci>
Color :: *ghci> :t (Red, Blue, Green)(Red, Blue, Green) :: (Color, Color, Color)ghci> :t (,,)(,,) :: a -> b -> c -> (a, b, c)ghci> :t (,,,)(,,,) :: a -> b -> c -> d -> (a, b, c, d)ghci> :t ()
Color :: *ghci> :t (Red, Blue, Green)(Red, Blue, Green) :: (Color, Color, Color)ghci> :t (,,)(,,) :: a -> b -> c -> (a, b, c)ghci> :t (,,,)(,,,) :: a -> b -> c -> d -> (a, b, c, d)ghci> :t ()() :: ()ghci>
Color :: *ghci> :t (Red, Blue, Green)(Red, Blue, Green) :: (Color, Color, Color)ghci> :t (,,)(,,) :: a -> b -> c -> (a, b, c)ghci> :t (,,,)(,,,) :: a -> b -> c -> d -> (a, b, c, d)ghci> :t ()() :: ()ghci> -- Trivial is similar to void.
data Either a b = Left a | Right b
Either (Sum)Color :: *ghci> :t (Red, Blue, Green)(Red, Blue, Green) :: (Color, Color, Color)ghci> :t (,,)(,,) :: a -> b -> c -> (a, b, c)ghci> :t (,,,)(,,,) :: a -> b -> c -> d -> (a, b, c, d)ghci> :t ()() :: ()ghci> -- Trivial is similar to void.ghci>
data Either a b = Left a | Right b
Either (Sum)
data Maybe a = Nothing | Just a
Maybe (Optional)
hue :: Color -> Doublehue Red = 0hue Green = 120hue Blue = 240
hue (Mix c c') = ... sometimes NaN
hue :: Color -> Doublehue Red = 0hue Green = 120hue Blue = 240
hue (Mix c c') = ... sometimes nothing
hue :: Color -> Maybe Doublehue Red = 0hue Green = 120hue Blue = 240
hue (Mix c c') = ... sometimes nothing
hue :: Color -> Maybe Doublehue Red = Just 0hue Green = Just 120hue Blue = Just 240
hue (Mix c c') = ... sometimes nothing
hue :: Color -> Maybe Doublehue Red = Just 0hue Green = Just 120hue Blue = Just 240
hue (Mix c c') = let ... stuff ... in case compare d 90 of LT -> m EQ -> nan GT -> m'
hue :: Color -> Maybe Doublehue Red = Just 0hue Green = Just 120hue Blue = Just 240
hue (Mix c c') = let ... stuff ... in case compare d 90 of LT -> Just m EQ -> nan GT -> Just m'
hue :: Color -> Maybe Doublehue Red = Just 0hue Green = Just 120hue Blue = Just 240
hue (Mix c c') = let ... stuff ... in case compare d 90 of LT -> Just m EQ -> Nothing GT -> Just m'
hue :: Color -> Maybe Doublehue Red = Just 0hue Green = Just 120hue Blue = Just 240
hue (Mix c c') = let h = hue c h' = hue c' ... stuff ... in case compare d 90 of LT -> Just m EQ -> Nothing GT -> Just m'
hue (Mix c c') = let h = hue c h' = hue c' ...
hue (Mix c c') = let h = hue c h' = hue c' ...
hue (Mix c c') = let (h, h') = (hue c, hue c') ...
hue (Mix c c') = case (hue c, hue c') of (h, h') -> let ...
hue (Mix c c') = case (hue c, hue c') of (Just h, Just h') -> let ...
hue (Mix c c') = case (hue c, hue c') of (Just h, Just h') -> let ... (Just h, Nothing) -> ... (Nothing, Just h') -> ... (Nothing, Nothing) -> ...
hue (Mix c c') = case (hue c, hue c') of (Just h, Just h') -> let ... (Just h, Nothing) -> Nothing (Nothing, Just h') -> Nothing (Nothing, Nothing) -> Nothing
hue (Mix c c') = case (hue c, hue c') of (Just h, Just h') -> let ... _ -> Nothing
hue (Mix c c') = case (hue c, hue c') of (Just h, Just h') -> let m = average h h' m' = norm (m + 180) d = distance h m in case compare d 90 of LT -> Just m EQ -> Nothing GT -> Just m' _ -> Nothing
Parametric Polymorphism
id x = x
const x _ = x
flip f x y = f y x
Parametric Polymorphismid :: a -> aid x = x
const x _ = x
flip f x y = f y x
Parametric Polymorphismid :: a -> aid x = x
const :: a -> b -> aconst x _ = x
flip f x y = f y x
Parametric Polymorphismid :: a -> aid x = x
const :: a -> b -> aconst x _ = x
flip :: (a -> b -> c) -> b -> a -> cflip f x y = f y x
Parametric Polymorphism
infixr . -- defaults to 9(f . g) x = f (g x)
Parametric Polymorphism(.) :: (b -> c) -> (a -> b) -> a -> cinfixr . -- defaults to 9(f . g) x = f (g x)
Parametric Polymorphism(.) :: (b -> c) -> (a -> b) -> a -> cinfixr . -- defaults to 9(f . g) x = f (g x)
isN :: Double -> BoolisN = not . isNaN
Parametric Polymorphism(.) :: (b -> c) -> (a -> b) -> a -> cinfixr . -- defaults to 9(f . g) x = f (g x)
isN :: Double -> BoolisN = not . isNaN
celsiusToFahrenheit :: Double -> DoublecelsiusToFahrenheit t = 9/5 * t + 32
Parametric Polymorphism(.) :: (b -> c) -> (a -> b) -> a -> cinfixr . -- defaults to 9(f . g) x = f (g x)
isN :: Double -> BoolisN = not . isNaN
celsiusToFahrenheit :: Double -> DoublecelsiusToFahrenheit t = 9/5 * t + 32celsiusToFahrenheit' = (32 +) . (9/5 *)
Parametric Polymorphism
infixr 0 $ -- very low precedence.f $ x = f x
Parametric Polymorphism($) :: (a -> b) -> a -> binfixr 0 $ -- very low precedence.f $ x = f x
Parametric Polymorphism($) :: (a -> b) -> a -> binfixr 0 $ -- very low precedence.f $ x = f x
-- Allows you to drop parenthesis:n = sqrt ( abs ( cos 1))n' = sqrt $ abs $ cos 1
data List a = Nil | Cons a (List a)
List (Stream)
List (Stream)
data [a] = [] | a:[a]-- Built-in syntax:-- definition only for illustrative purposes.
List (Stream)
data [a] = [] | a:[a]-- Built-in syntax:-- definition only for illustrative purposes.
ghci> [1,2,3]
ghci> [1,2,3][1,2,3]ghci>
ghci> [1,2,3][1,2,3]ghci> 1:[2,3]
ghci> [1,2,3][1,2,3]ghci> 1:[2,3][1,2,3]ghci>
ghci> [1,2,3][1,2,3]ghci> 1:[2,3][1,2,3]ghci> 1:2:3:[]
ghci> [1,2,3][1,2,3]ghci> 1:[2,3][1,2,3]ghci> 1:2:3:[][1,2,3]ghci>
ghci> [1,2,3][1,2,3]ghci> 1:[2,3][1,2,3]ghci> 1:2:3:[][1,2,3]ghci> :t (:)
ghci> [1,2,3][1,2,3]ghci> 1:[2,3][1,2,3]ghci> 1:2:3:[][1,2,3]ghci> :t (:)(:) :: a -> [a] -> [a]ghci>
ghci> [1,2,3][1,2,3]ghci> 1:[2,3][1,2,3]ghci> 1:2:3:[][1,2,3]ghci> :t (:)(:) :: a -> [a] -> [a]ghci> :t []
Characters
c = 'c'six = '6'tab = '\t'
isSpace, isAlpha, isDigit :: Char -> Boolord :: Char -> Intchr :: Int -> Char
ghci> [1,2,3][1,2,3]ghci> 1:[2,3][1,2,3]ghci> 1:2:3:[][1,2,3]ghci> :t (:)(:) :: a -> [a] -> [a]ghci> :t [][] :: [a]ghci>
Characters
c = 'c'six = '6'tab = '\t'
isSpace, isAlpha, isDigit :: Char -> Boolord :: Char -> Intchr :: Int -> Char
Strings (Type Synonym)
type String = [Char]
Strings (Type Synonym)
type String = [Char]
ghci> :info String
ghci> :info Stringtype String = [Char] !-- Defined in GHC.Baseghci>
ghci> :info Stringtype String = [Char] !-- Defined in GHC.Baseghci> ['h', 'e', 'l', 'l', 'o']
ghci> :info Stringtype String = [Char] !-- Defined in GHC.Baseghci> ['h', 'e', 'l', 'l', 'o']"hello"ghci>
ghci> :info Stringtype String = [Char] !-- Defined in GHC.Baseghci> ['h', 'e', 'l', 'l', 'o']"hello"ghci> :t error
ghci> :info Stringtype String = [Char] !-- Defined in GHC.Baseghci> ['h', 'e', 'l', 'l', 'o']"hello"ghci> :t errorerror :: [Char] -> aghci>
ghci> :info Stringtype String = [Char] !-- Defined in GHC.Baseghci> ['h', 'e', 'l', 'l', 'o']"hello"ghci> :t errorerror :: [Char] -> aghci> error "oops"
one_ten = [1..10]a_z = ['a'..'z']
Arithmetic Sequencesghci> :info Stringtype String = [Char] !-- Defined in GHC.Baseghci> ['h', 'e', 'l', 'l', 'o']"hello"ghci> :t errorerror :: [Char] -> aghci> error "oops"*** Exception: oopsghci>
one_ten = [1..10]a_z = ['a'..'z']
Arithmetic Sequences
nats = [1..]
Arithmetic Sequences
Length
length :: [a] -> Intlength [] = 0length (_:xs) = 1 + length xs
length one_ten --> 10length a_z --> 26
Map
map :: (a -> b) -> [a] -> [b]map f [] = []map f (x:xs) = f x : map f xs
map ord "abc" --> [97, 98, 99]
Append
(++) :: [a] -> [a] -> [a]infixr 5 ++[] ++ ys = ys(x:xs) ++ ys = x : (xs ++ ys)
"hello" ++ " " ++ "world" --> "hello world"
Filter
filter :: (a -> Bool) -> [a] -> [a]filter p [] = []filter p (x:xs) | p x = x : filter p xs | otherwise = filter p xs
filter (> 7) one_ten --> [8, 9, 10]
Fold
foldr :: (a -> b -> b) -> b -> [a] -> bfoldr f z [] = zfoldr f z (x:xs) = f x (foldr f x xs)
foldr (*) 1 [1..5] --> 120
Concat (Flattening)
concat :: [[a]] -> [a]concat = foldr (++) []
concat ["hello", ", ", "world"] --> "hello, world"
ListComprehensions
List Comprehensions
divides x y = rem y x == 0
divisors x = [d | d <- [1..x], d `divides` x]
Generators
[ (a, a, a) | a <- nats]
[(1,1,1),(2,2,2),(3,3,3),⋯]
Generators
[ (a, b, c) | a <- nats, b <- nats, c <- nats]
[(1,1,1),(1,1,2),(1,1,3),⋯]
Generators
[ (a, b, c) | a <- nats, b <- nats, c <- nats]
[(1,1,1),(1,1,2),(1,1,3),⋯]
(1,2,3) (1,3,2)(2,1,3) (3,1,2)(2,3,1) (3,2,1)
Generators
[ (a, b, c) | a <- nats, b <- [1..a], c <- [1..b]]
[(1,1,1),(2,1,1),(2,2,1),⋯]
Generators
[ (a, b, c) | c <- nats, b <- [1..c], a <- [1..b]]
[(1,1,1),(1,1,2),(1,2,2),⋯]
Guards
[ (a, b, c) | c <- nats, b <- [1..c], a <- [1..b], a^2 + b^2 == c^2]
[(3,4,5),(6,8,10),(5,12,13),⋯]
Local Declaration
[ (a, b, c) | c <- nats, b <- [1..c], a <- [1..b], a^2 + b^2 == c^2, ... commonDivisors == [1]]
[(3,4,5),(5,12,13),(8,15,17),⋯]
Local Declaration
[ (a, b, c) | c <- nats, b <- [1..c], a <- [1..b], a^2 + b^2 == c^2, let commonDivisors = [d | d <- divisors a, d `divides` b, d `divides` c], commonDivisors == [1]]
[(3,4,5),(5,12,13),(8,15,17),⋯]
Local Declaration
[ (a, b, c) | c <- nats, b <- [1..c], a <- [1..b], a^2 + b^2 == c^2, let d = gcd a b, d == 1]
[(3,4,5),(5,12,13),(8,15,17),⋯]
Recursion
primes = sieve [2..] where sieve (p:xs) = p : sieve [x | x <- xs, rem x p /= 0]
Recursion
primes = sieve [2..] where sieve (p:xs) = p : sieve [x | x <- xs, rem x p /= 0]
primes
Recursion
primes = sieve [2..] where sieve (p:xs) = p : sieve [x | x <- xs, rem x p /= 0]
sieve [2..]
Recursion
primes = sieve [2..] where sieve (p:xs) = p : sieve [x | x <- xs, rem x p /= 0]
sieve (2:[3..])
Recursion
primes = sieve [2..] where sieve (p:xs) = p : sieve [x | x <- xs, rem x p /= 0]
2 : sieve [x | x <- [3..], rem x 2 /= 0]
Recursion
primes = sieve [2..] where sieve (p:xs) = p : sieve [x | x <- xs, rem x p /= 0]
2 : sieve [x | x <- 3:[4..], rem x 2 /= 0]
Recursion
primes = sieve [2..] where sieve (p:xs) = p : sieve [x | x <- xs, rem x p /= 0]
2 : sieve (3:[x | x <- [4..], rem x 2 /= 0])
Recursion
primes = sieve [2..] where sieve (p:xs) = p : sieve [x | x <- xs, rem x p /= 0]
2 : 3 : sieve [x | x <- [x | x <- [4..], rem x 2 /= 0], rem x 3 /= 0]
Recursion
primes = sieve [2..] where sieve (p:xs) = p : sieve [x | x <- xs, rem x p /= 0]
2 : 3 : sieve [x | x <- [x | x <- 4:[5..], rem x 2 /= 0], rem x 3 /= 0]
Recursion
primes = sieve [2..] where sieve (p:xs) = p : sieve [x | x <- xs, rem x p /= 0]
2 : 3 : sieve [x | x <- [x | x <- [5..], rem x 2 /= 0], rem x 3 /= 0]
Recursion
primes = sieve [2..] where sieve (p:xs) = p : sieve [x | x <- xs, rem x p /= 0]
2 : 3 : sieve [x | x <- [x | x <- 5:[6..], rem x 2 /= 0], rem x 3 /= 0]
Recursion
primes = sieve [2..] where sieve (p:xs) = p : sieve [x | x <- xs, rem x p /= 0]
2 : 3 : sieve [x | x <- 5:[x | x <- [6..], rem x 2 /= 0], rem x 3 /= 0]
Recursion
primes = sieve [2..] where sieve (p:xs) = p : sieve [x | x <- xs, rem x p /= 0]
2 : 3 : sieve (5:[x | x <- [x | x <- [6..], rem x 2 /= 0], rem x 3 /= 0])
Recursion
primes = sieve [2..] where sieve (p:xs) = p : sieve [x | x <- xs, rem x p /= 0]
2 : 3 : 5 : sieve [x | x <- [x | x <- [x | x <- [6..], rem x 2 /= 0], rem x 3 /= 0]), rem x 5 /= 0]
Recursion
primes = sieve [2..] where sieve (p:xs) = p : sieve [x | x <- xs, rem x p /= 0]
2 : 3 : 5 : sieve [x | x <- [x | x <- [x | x <- 6:[7..], rem x 2 /= 0], rem x 3 /= 0]), rem x 5 /= 0]
Recursion
primes = sieve [2..] where sieve (p:xs) = p : sieve [x | x <- xs, rem x p /= 0]
2 : 3 : 5 : sieve [x | x <- [x | x <- [x | x <- [7..], rem x 2 /= 0], rem x 3 /= 0]), rem x 5 /= 0]
Recursion
primes = sieve [2..] where sieve (p:xs) = p : sieve [x | x <- xs, rem x p /= 0]
2 : 3 : 5 : sieve [x | x <- [x | x <- [x | x <- 7:[8..], rem x 2 /= 0], rem x 3 /= 0]), rem x 5 /= 0]
Recursion
primes = sieve [2..] where sieve (p:xs) = p : sieve [x | x <- xs, rem x p /= 0]
2 : 3 : 5 : sieve [x | x <- [x | x <- 7:[x | x <- [8..], rem x 2 /= 0], rem x 3 /= 0]), rem x 5 /= 0]
Recursion
primes = sieve [2..] where sieve (p:xs) = p : sieve [x | x <- xs, rem x p /= 0]
2 : 3 : 5 : sieve [x | x <- 7:[x | x <- [x | x <- [8..], rem x 2 /= 0], rem x 3 /= 0]), rem x 5 /= 0]
Recursion
primes = sieve [2..] where sieve (p:xs) = p : sieve [x | x <- xs, rem x p /= 0]
2 : 3 : 5 : sieve (7:[x | x <- [x | x <- [x | x <- [8..], rem x 2 /= 0], rem x 3 /= 0]), rem x 5 /= 0])
Recursion
primes = sieve [2..] where sieve (p:xs) = p : sieve [x | x <- xs, rem x p /= 0]
2 : 3 : 5 : 7 : sieve ⋯
Recursion
primes = sieve [2..] where sieve (p:xs) = p : sieve [x | x <- xs, rem x p /= 0]
[2, 3, 5, 7, sieve ⋯]
To be continued...
Summary
Haskell has parametric types.
List Comprehensions are cool.
Preview: Infinite Lists
primes = sieve [2..] where sieve (p:xs) = p : sieve [x | x <- xs, rem x p /= 0]
Preview: IO (echo.hs)
import System.Environment (getArgs)import Data.List (intercalate)
main = do args <- getArgs putStrLn (intercalate " " args)
Preview: Parsers
Preview: Parse JSON
data Value = String String | Number Double | Object [(String, Value)] | Array [Value] | Bool Bool | Null
Preview: Parse JSON
value = String <$> jsstring <|> Number <$> number <|> Object <$> commaGroup '{' pair '}' <|> Array <$> commaGroup '[' value ']' <|> Bool True <$ string "true" <|> Bool False <$ string "false" <|> Null <$ string "null"
Preview: Parse JSON
pair :: Parser (String, Value)pair = do s <- jsstring sp_char_sp ':' v <- value spaces return (s, v)
To be continued...