haskell tour (part 2)

Post on 29-Aug-2014

2.417 Views

Category:

Technology

3 Downloads

Preview:

Click to see full reader

DESCRIPTION

We continue our introduction to Haskell. Today we talk about parametric types and list comprehensions.

TRANSCRIPT

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...

top related