Haskell Tour (Part 1)

Post on 05-Sep-2014

4.326 views 4 download

Tags:

description

We introduce Haskell. Why is it interesting. Where did it come from. What is it like. How to get started. We show a GHCi session. We introduce simple recursive function and data. And we demo QuickCheck for testing properties of automatically generated data.

Transcript of Haskell Tour (Part 1)

HaskellA Whirlwind Tour

William Taysom2011

Haskell

Haskell

Who?

What?

When?

Where?

Why?

How?

Haskell

Who?

What?

When?

Where?

Why?

How?

Why?

Aesthetics

Why? Aesthetics

“We provided DARPA with a copy of our prototype implemented in Haskell without explaining that it was a program, and based on preconceptions from their past experience, they had studied the program under the assumption that it was a mixture of requirements specification and top level design. They were convinced it was incomplete because it did not address issues such as data structure design and execution order.”

— Paul Hudak

Why? Aesthetics

“Take Lisp: you know it's the most beautiful language in the world. At least up until Haskell came along.”

— Larry Wall

Why? Aesthetics

“Reading Haskell is like reading poetry.Writing Haskell is like writing poetry.”

— Oliver Steele

Why? Aesthetics

“I also have interest in Haskell, but my brain just explodes every time I read a Haskell program bigger than ten lines.”

— Matz

Why? Aesthetics

“The biggest advantage of Haskell to me is that it helps me write better programs in other languages.”

— Tenerife Skunkworks

Why? Aesthetics

.NET LINQ

Python List Comprehensions

Java Generics

JavaScript jQuery

Why?

Pragmatics

Why? Pragmatics

Platform Compiler Debugger Profiler Testing

Libraries Network Graphics Hackage

Community Books Documentation Hoogle

Why? Pragmatics

Platform Compiler Debugger Profiler Testing

Libraries Network Graphics Hackage

Community Books Documentation Hoogle

Why? PragmaticsHoogle

Why? PragmaticsHoogle

Why? Pragmatics

Platform Compiler Debugger Profiler Testing

Libraries Network Graphics Hackage

Community Books Documentation Hoogle

Why? Pragmatics

Platform Compiler Debugger Profiler Testing

Libraries Network Graphics Hackage

Community Books Documentation Hoogle

How?

GHCDocumentation

LibrariesCabal

Hackage

Why? Pragmatics

Platform Compiler Debugger Profiler Testing

Libraries Network Graphics Hackage

Community Books Documentation Hoogle

Why? Pragmatics

Why? Pragmatics

Why? Pragmatics

“A programming language must be considered in the context of its community, and Haskell has an exemplary one. I have come to believe, however, that this polite exterior conceals a deep and consuming madness.”

— Avdi Grimm

Why?

Performance

Why? PerformanceThe Computer Language Benchmarks Game

Web ServerPong benchmark, extra large instance, requests/second

Why? Performance

Web ServerPong benchmark, extra large instance, requests/second

Why? Performance

Why?

AestheticsPragmatics

Performance

Haskell

Who?

What?

When?

Where?

Why? Aesthetics Pragmatics Performance

How?

Haskell

Who?

What?

When?

Where?

Why? Aesthetics Pragmatics Performance

How?

Who? When? Where?

September 1987

Who? When? Where?

Portland, Oregon

Who? When? Where?

Functional Programming Languages and Computer Architecture Conference

Who? When? Where?

A Dozen PurelyFunctional Languages

Who? When? Where?

All Similar

Who? When? Where? Committee Formed

Who? When? Where? Committee Formed

Provide faster communication of new ideas.

Stable foundation for real application development.

Vehicle through which others would be encouraged to use functional languages.

Who? When? Where?

Haskell ReportApril 1st 1990

“You know, Haskell actually never liked the name Haskell.”

— Mary Curry

Who? When? Where?

2002

Revised Haskell 98 Report

Who? When? Where?

2010

Haskell'

Haskell

Who? Research Wadler Hudak Peyton-Jones

What?

When? 1987 1990 2002 Now

Where? Portland Glasgow Microsoft

Why? Aesthetics Pragmatics Performance

How?

Haskell

Who? Research Wadler Hudak Peyton-Jones

What?

When? 1987 1990 2002 Now

Where? Portland Glasgow Microsoft

Why? Aesthetics Pragmatics Performance

How?

What?

A non-strict, purely functional programming language with strong,static type inference.

What?

A non-strict, purely functional programming language with strong,static type inference.

What? Programming

Source Code

Formal, Textural Syntax

Static & Runtime Semantics

Data, Variables, Lexical Scope

Interpreter, Compiler

What?

A non-strict, purely functional programming language with strong,static type inference.

What?

A non-strict, purely functional programming language with strong,static type inference.

What? Functional

(Not Imperative)

What? Functional

Imperative Statements Executed Step-by-step

What? Functional

Imperative Statements Executed Step-by-step

Modifying State

What? Functional

Imperative Statements Executed Step-by-step

Modifying State

Turing Machine

What? Functional

Imperative Statements Executed Step-by-step

Modifying State

Von Neumann Architecture

What? Functional

Imperative Statements Executed Step-by-step

Modifying State

Von Neumann Architecture

Functional Expressions Recursively Simplified

What? Functional

Imperative Statements Executed Step-by-step

Modifying State

Von Neumann Architecture

Functional Expressions Recursively Simplified

Reduced Value

What? Functional

Imperative Statements Executed Step-by-step

Modifying State

Von Neumann Architecture

Functional Expressions Recursively Simplified

Reduced Value

Lambda Calculus

Imperative Statements Executed Step-by-step

Modifying State

Von Neumann Architecture

Functional Expressions Recursively Simplified

Reduced Value

Lambda Calculus

What? Functional

Imperative Statements Executed Step-by-step

Modifying State

Von Neumann Architecture

Functional Expressions Recursively Simplified

Reduced Value

Lambda Calculus

What? Functional

What?

A non-strict, purely functional programming language with strong,static type inference.

What?

A non-strict, purely functional programming language with strong,static type inference.

What? Pure

(No Side Effects)

What? Pure

Immutable Only

What? Pure

Referential Transparency

What? Pure

Functions alwaysreturn the same value.

If v = f x, then you canalways replace f x with v.

What? Pure

Functions alwaysreturn the same value.

If v equals f x, then you canalways replace f x with v.

What?

A non-strict, purely functional programming language with strong,static type inference.

What?

A non-strict, purely functional programming language with strong,static type inference.

What? Non-strict

Be lazy.

What? Non-strict

Be lazy.

Ignore evaluation order.

Wait...

if everything is immutable and there

are no side effects and evaluation is lazy,

then how the hell do you do anything?

M O N A D SBring your own Semicolon

What? Monads

What? Monads

What? Monads

What? Monads

What? Monads

What? Monads

“Haskell is the world's finestimperative programming language.”

— Simon Peyton-Jones

What? Monads

“Haskell is the only language I know withfirst-class support for imperative programming.”

— SamB

What? Monads

“Haskell has no preferred imperative semantics, and the monad just lets you swap out the semantics according to your needs.”

— Jared Updike

What?

A non-strict, purely functional programming language with strong,static type inference.

What?

A non-strict, purely functional programming language with strong,static type inference.

What? Types

StrongStatic

Inference

What? Types

StrongStatic

Inference

What? Strong Types

Runtime valueshave types.

What? Strong Types

Runtime valueshave types.

like Java and Rubyunlike C and Assembly

(Not Weak)

What? Types

StrongStatic

Inference

What? Types

StrongStatic

Inference

What? Static Types

Source code expressionshave types.

What? Static Types

Source code expressionshave types.

like C and Javaunlike Ruby and JavaScript

(Not Dynamic)

What? Types

StrongStatic

Inference

What? Types

StrongStatic

Inference

What? Type Inference

Automatically determines types of variables.

What? Type Inference

Automatically determines types of variables.

like C# and Gounlike C and Java

(Not Manifest)

You don’t need totype the type!

S Y N E R G YPurity means types tell you a lot.

What? Type Purity

No side effectsmean,

What? Type Purity

No side effectsmean,

argument and returntypes limit what

a function can do.

What? Type Purity

“Haskell is so strict about type safety that randomly generated snippets of code that successfully type check are likely to do something useful, even if you've no idea what that useful thing is.”

— sigfpe

What? Type Purity

“Since when does "it compiles" equate to "it will run (correctly)"? We're talking about C, after all, not Haskell.”

— Sean Russell

What? Types

StrongStatic

Inference

What?

A non-strict, purely functional programming language with strong,static type inference.

What?

A non-strict, purely functional programming language with strong,static type inference.

Haskell

Who? Research Wadler Hudak Peyton-Jones

What? Non-strict Purely Functional Static Types

When? 1987 1990 2002 Now

Where? Portland Glasgow Microsoft

Why? Aesthetics Pragmatics Performance

How?

Haskell

Who? Research Wadler Hudak Peyton-Jones

What? Non-strict Purely Functional Static Types

When? 1987 1990 2002 Now

Where? Portland Glasgow Microsoft

Why? Aesthetics Pragmatics Performance

How?

How?

Just Downloadand Install

the Platform

How?

Just Downloadand Install

the Platform

Glorious Glasgow Haskell Compilation

System

GHC

Compiler ghc

Interactive ghci

Scripts runghc

GHC

Compiler ghc

Interactive ghci

Scripts runghc

Haskell

Who? Research Wadler Hudak Peyton-Jones

What? Non-strict Purely Functional Static Types

When? 1987 1990 2002 Now

Where? Portland Glasgow Microsoft

Why? Aesthetics Pragmatics Performance

How? Platform Hoogle Hackage

Haskell

Who? Research Wadler Hudak Peyton-Jones

What? Non-strict Purely Functional Static Types

When? 1987 1990 2002 Now

Where? Portland Glasgow Microsoft

Why? Aesthetics Pragmatics Performance

How? Platform Hoogle Hackage

Example

Example

┼ $

$ ghci

$ ghciGHCi, version 7.0.2: http://www.haskell.org/ghc/ :? for helpLoading package ghc-prim ... linking ... done.Loading package integer-gmp ... linking ... done.Loading package base ... linking ... done.Loading package ffi-1.0 ... linking ... done.ghci>

$ ghciGHCi, version 7.0.2: http://www.haskell.org/ghc/ :? for helpLoading package ghc-prim ... linking ... done.Loading package integer-gmp ... linking ... done.Loading package base ... linking ... done.Loading package ffi-1.0 ... linking ... done.ghci> "hello, world"

$ ghciGHCi, version 7.0.2: http://www.haskell.org/ghc/ :? for helpLoading package ghc-prim ... linking ... done.Loading package integer-gmp ... linking ... done.Loading package base ... linking ... done.Loading package ffi-1.0 ... linking ... done.ghci> "hello, world""hello, world"ghci>

"hello, world"ghci>

"hello, world"ghci> 6 * 9

"hello, world"ghci> 6 * 942ghci>

"hello, world"ghci> 6 * 942ghci> [1, 2, 3]

"hello, world"ghci> 6 * 942ghci> [1, 2, 3][1,2,3]ghci>

"hello, world"ghci> 6 * 942ghci> [1, 2, 3][1,2,3]ghci> it

"hello, world"ghci> 6 * 942ghci> [1, 2, 3][1,2,3]ghci> it[1,2,3]ghci>

“Function application is so important in Haskell that we denote it using the quietest possible syntax: nothing at all.”

— Simon Peyton-Jones

"hello, world"ghci> 6 * 942ghci> [1, 2, 3][1,2,3]ghci> it[1,2,3]ghci> reverse it

“Function application is so important in Haskell that we denote it using the quietest possible syntax: nothing at all.”

— Simon Peyton-Jones

“Function application is so important in Haskell that we denote it using the quietest possible syntax: nothing at all.”

— Simon Peyton-Jones

"hello, world"ghci> 6 * 942ghci> [1, 2, 3][1,2,3]ghci> it[1,2,3]ghci> reverse it

"hello, world"ghci> 6 * 942ghci> [1, 2, 3][1,2,3]ghci> it[1,2,3]ghci> reverse it[3,2,1]ghci>

[3,2,1]ghci>

[3,2,1]ghci> let xs = [1..100]

[3,2,1]ghci> let xs = [1..100]ghci>

[3,2,1]ghci> let xs = [1..100]ghci> xs

[3,2,1]ghci> let xs = [1..100]ghci> xs[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100]ghci>

[3,2,1]ghci> let xs = [1..100]ghci> xs[1,2,⋯,99,100]ghci>

[3,2,1]ghci> let xs = [1..100]ghci> xs[1,2,⋯,99,100]ghci> [x | x <- xs, x > 21]

[3,2,1]ghci> let xs = [1..100]ghci> xs[1,2,⋯,99,100]ghci> [x | x <- xs, x > 21][22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100]ghci>

[3,2,1]ghci> let xs = [1..100]ghci> xs[1,2,⋯,99,100]ghci> [x | x <- xs, x > 21][22,23,⋯,99,100]ghci>

[3,2,1]ghci> let xs = [1..100]ghci> xs[1,2,⋯,99,100]ghci> [x | x <- xs, x > 21][22,23,⋯,99,100]ghci> filter (> 21) xs

[3,2,1]ghci> let xs = [1..100]ghci> xs[1,2,⋯,99,100]ghci> [x | x <- xs, x > 21][22,23,⋯,99,100]ghci> filter (> 21) xs[22,23,⋯,99,100]ghci>

[3,2,1]ghci> let xs = [1..100]ghci> xs[1,2,⋯,99,100]ghci> [x | x <- xs, x > 21][22,23,⋯,99,100]ghci> filter (> 21) xs[22,23,⋯,99,100]ghci> filter (\x -> x > 21) xs

TMTOWTDI

[3,2,1]ghci> let xs = [1..100]ghci> xs[1,2,⋯,99,100]ghci> [x | x <- xs, x > 21][22,23,⋯,99,100]ghci> filter (> 21) xs[22,23,⋯,99,100]ghci> filter (\x -> x > 21) xs[22,23,⋯,99,100]ghci>

TMTOWTDI

1. Freshman2. Sophomore3. Junior (Peano)4. Junior (Ban n+k)5. Senior (Leans Right)6. Senior (Leans Left)7. Senior (Leans Around)8. Memoizing9. Points-free10. Iterative11. Iterative one-liner12. Accumulating

13. Continuation-passing14. Boy Scout15. Combinatory16. List-encoding17. Interpretive18. Static19. Beginning Graduate20. Origamist21. Cartesianally-inclined22. Ph.D.23. Post-doc24. Tenured Professor

The Evolution of a Haskell Programmer

TMTOWTDI

TMTOWTDI

[3,2,1]ghci> let xs = [1..100]ghci> xs[1,2,⋯,99,100]ghci> [x | x <- xs, x > 21][22,23,⋯,99,100]ghci> filter (> 21) xs[22,23,⋯,99,100]ghci> filter (\x -> x > 21) xs[22,23,⋯,99,100]ghci>

[22,23,⋯,99,100]ghci>

[22,23,⋯,99,100]ghci> let divides = \x y -> rem y x == 0

[22,23,⋯,99,100]ghci> let divides = \x y -> rem y x == 0ghci>

[22,23,⋯,99,100]ghci> let divides = \x y -> rem y x == 0ghci> let divides x y = rem y x == 0

[22,23,⋯,99,100]ghci> let divides = \x y -> rem y x == 0ghci> let divides x y = rem y x == 0ghci>

[22,23,⋯,99,100]ghci> let divides = \x y -> rem y x == 0ghci> let divides x y = rem y x == 0ghci> divides 3 12

[22,23,⋯,99,100]ghci> let divides = \x y -> rem y x == 0ghci> let divides x y = rem y x == 0ghci> divides 3 12Trueghci>

[22,23,⋯,99,100]ghci> let divides = \x y -> rem y x == 0ghci> let divides x y = rem y x == 0ghci> divides 3 12Trueghci> 3 `divides` 12

[22,23,⋯,99,100]ghci> let divides = \x y -> rem y x == 0ghci> let divides x y = rem y x == 0ghci> divides 3 12Trueghci> 3 `divides` 12Trueghci>

[22,23,⋯,99,100]ghci> let divides = \x y -> rem y x == 0ghci> let divides x y = rem y x == 0ghci> divides 3 12Trueghci> 3 `divides` 12Trueghci> let divisors x = [d | d <- [1..x], d `divides` x]

[22,23,⋯,99,100]ghci> let divides = \x y -> rem y x == 0ghci> let divides x y = rem y x == 0ghci> divides 3 12Trueghci> 3 `divides` 12Trueghci> let divisors x = [d | d <- [1..x], d `divides` x]ghci>

[22,23,⋯,99,100]ghci> let divides = \x y -> rem y x == 0ghci> let divides x y = rem y x == 0ghci> divides 3 12Trueghci> 3 `divides` 12Trueghci> let divisors x = [d | d <- [1..x], d `divides` x]ghci> divisors 100

Fundamentals

[22,23,⋯,99,100]ghci> let divides = \x y -> rem y x == 0ghci> let divides x y = rem y x == 0ghci> divides 3 12Trueghci> 3 `divides` 12Trueghci> let divisors x = [d | d <- [1..x], d `divides` x]ghci> divisors 100[1,2,4,5,10,20,25,50,100]ghci>

Fundamentals

Data Declaration

data Color = Red | Green | Blue

Variables

red = Red-- Lower case for variable and upper case for constructor.

nan = 0 / 0-- Variables stand for values. They do not label locations.-- Don't need let because we aren't at GHCi.-- Declarations go at top-level, not expressions. (Like Java, unlike Ruby.)

Functions

hue Red = 0hue Green = 120hue Blue = 240

Lambda & Case

hue = \c -> case c of Red -> 0 Green -> 120 Blue -> 240

Pattern Wildcard

isRed Red = TrueisRed _ = False

Boolean Data

data Bool = True | False

Boolean Functions

otherwise = True

not True = Falsenot False = True

Boolean Operators

True && x = xFalse && _ = False

(||) True _ = True(||) False x = x-- Parenthesis let us use operators prefix.

Operator Precedence

infixr 3 &&infixr 2 ||

-- Ten precedence levels: 0 binds least tightly, 9 (default) binds most tightly.

-- Three associativities: infixl (default), infixr, infix (non-associative).

Types

“Types in Haskell express high-level design in the same way that UML diagrams do in Object Oriented languages.”

— Simon Peyton-Jones

Types

“Types in Haskell express high-level design in the same way that UML diagrams do in Object Oriented languages.”

— Simon Peyton-Jones

ghci> :l example

ghci> :l example[1 of 1] Compiling Main ( example.hs, interpreted )Ok, modules loaded: Main.ghci>

ghci> :l example[1 of 1] Compiling Main ( example.hs, interpreted )Ok, modules loaded: Main.ghci> :r

ghci> :l example[1 of 1] Compiling Main ( example.hs, interpreted )Ok, modules loaded: Main.ghci> :rOk, modules loaded: Main.ghci>

ghci> :l example[1 of 1] Compiling Main ( example.hs, interpreted )Ok, modules loaded: Main.ghci> :rOk, modules loaded: Main.ghci> :type red

ghci> :l example[1 of 1] Compiling Main ( example.hs, interpreted )Ok, modules loaded: Main.ghci> :rOk, modules loaded: Main.ghci> :type redRed :: Colorghci>

ghci> :l example[1 of 1] Compiling Main ( example.hs, interpreted )Ok, modules loaded: Main.ghci> :rOk, modules loaded: Main.ghci> :type redRed :: Colorghci> :t isRed

red :: Colornan :: Double

hue :: Color -> Double

otherwise :: Boolnot :: Bool -> Bool(&&), (||) :: Bool -> Bool -> Bool

Typesghci> :l example[1 of 1] Compiling Main ( example.hs, interpreted )Ok, modules loaded: Main.ghci> :rOk, modules loaded: Main.ghci> :type redRed :: Colorghci> :t isRedisRed :: Color -> Boolghci>

red :: Colornan :: Double

hue :: Color -> Double

otherwise :: Boolnot :: Bool -> Bool(&&), (||) :: Bool -> Bool -> Bool

Types

Recursive Data

data Color = Red | Green | Blue | Mix Color Color

Recursive Data

data Color = Red | Green | Blue | Mix Color Color

mix :: Color -> Color -> Colormix = Mix-- Mix is a type constructor function.

Recursive Data

yellow, cyan, magenta :: Coloryellow = Mix Red Green

Mix cyan magenta = Mix (Mix Green Blue) (Mix Red Blue)-- Constructor functions can be used for pattern matching, but variables bind.

Recursive Functions

isRed :: Color -> BoolisRed Red = TrueisRed (Mix c c') = isRed c && isRed c'isRed _ = False

Recursive Functions

hue :: Color -> Doublehue Red = 0hue Green = 120hue Blue = 240

Recursive Functions

hue :: Color -> Doublehue Red = 0hue Green = 120hue Blue = 240

hue (Mix c c') = ???

hue (Mix c c') = ???

h

hue (Mix c c') = ???

h

hue (Mix c c') = let h = hue c ???

h

hue (Mix c c') = let h = hue c ???

h'

h

hue (Mix c c') = let h = hue c h' = hue c' ???

h'

h

hue (Mix c c') = let h = hue c h' = hue c' ???

h' m

hue (Mix c c') = let h = hue c h' = hue c' m = average h h' ???

h

h' m

h

h' mhue (Mix c c') = let h = hue c h' = hue c' m = average h h' average x y = abs (x + y) / 2 ???

h

h' mhue (Mix c c') = let h = hue c h' = hue c' m = average h h' average x y = abs (x + y) / 2 in m

h

h' mhue (Mix c c') = let h = hue c h' = hue c' m = average h h' average x y = abs (x + y) / 2 in ??!

h

m

h'

hue (Mix c c') = let h = hue c h' = hue c' m = average h h' average x y = abs (x + y) / 2 in ??!

h

m

h'

hue (Mix c c') = let h = hue c h' = hue c' m = average h h' average x y = abs (x + y) / 2 in ??!

m'

h

m

h' m'

hue (Mix c c') = let h = hue c h' = hue c' m = average h h' m' = m + 180 average x y = abs (x + y) / 2 in ??!

h

m

h' m'

hue (Mix c c') = let h = hue c h' = hue c' m = average h h' m' = m + 180 average x y = abs (x + y) / 2 in ??!

d

h

m

h' m'

dhue (Mix c c') = let h = hue c h' = hue c' m = average h h' m' = m + 180 d = distance h m average x y = abs (x + y) / 2 in ??!

h

m

h' m'

dhue (Mix c c') = let h = hue c h' = hue c' m = average h h' m' = m + 180 d = distance h m average x y = abs (x + y) / 2 distance x y = abs (x - y) in ??!

h

m

h' m'

dhue (Mix c c') = let h = hue c h' = hue c' m = average h h' m' = m + 180 d = distance h m average x y = abs (x + y) / 2 distance x y = abs (x - y) in case compare d 90 of LT -> m EQ -> ??! GT -> m'

h

m

h' m'

dhue (Mix c c') = let h = hue c h' = hue c' m = average h h' m' = m + 180 d = distance h m average x y = abs (x + y) / 2 distance x y = abs (x - y) in case compare d 90 of LT -> m EQ -> nan GT -> m'

h

m

h' m'

dhue (Mix c c') = r where r = case compare d 90 of LT -> m EQ -> nan GT -> m' h = hue c h' = hue c' m = average h h' m' = m + 180 d = distance h m average x y = abs (x + y) / 2distance x y = abs (x - y)

test-framework organize tests

HUnit what you’re used to

QuickCheck test properties with

automatically generated data

Testing

QuickCheck

prop_hue_bounds c = let h = hue c in isNaN h || 0 <= h && h < 360

QuickCheck

prop_hue_bounds c = let h = hue c in isNaN h || 0 <= h && h < 360

prop_hue_mix_reflexivity c = let h = hue c in isNaN h || hue (Mix c c) == h

QuickCheck

prop_hue_bounds c = let h = hue c in isNaN h || 0 <= h && h < 360

prop_hue_mix_reflexivity c = let h = hue c in isNaN h || hue (Mix c c) == h

prop_hue_mix_commutativity c c' = let h = hue (Mix c c') in isNaN h || hue (Mix c' c) == h

QuickCheck

prop_hue_bounds c = let h = hue c in isNaN h || 0 <= h && h < 360

prop_hue_mix_reflexivity c = let h = hue c in isNaN h || hue (Mix c c) == h

prop_hue_mix_commutativity c c' = let h = hue (Mix c c') in isNaN h || hue (Mix c' c) == h

ghci> quickCheck prop_hue_mix_commutativity

ghci> quickCheck prop_hue_mix_commutativity+++ OK, passed 100 tests.ghci>

ghci> quickCheck prop_hue_mix_commutativity+++ OK, passed 100 tests.ghci> quickCheck prop_hue_mix_reflexivity

ghci> quickCheck prop_hue_mix_commutativity+++ OK, passed 100 tests.ghci> quickCheck prop_hue_mix_reflexivity+++ OK, passed 100 tests.ghci>

ghci> quickCheck prop_hue_mix_commutativity+++ OK, passed 100 tests.ghci> quickCheck prop_hue_mix_reflexivity+++ OK, passed 100 tests.ghci> quickCheck prop_hue_bounds

ghci> quickCheck prop_hue_mix_commutativity+++ OK, passed 100 tests.ghci> quickCheck prop_hue_mix_reflexivity+++ OK, passed 100 tests.ghci> quickCheck prop_hue_bounds*** Failed! Falsifiable (after 3 tests): Mix (Mix Red Blue) (Mix Green Red)ghci>

ghci> quickCheck prop_hue_mix_commutativity+++ OK, passed 100 tests.ghci> quickCheck prop_hue_mix_reflexivity+++ OK, passed 100 tests.ghci> quickCheck prop_hue_bounds*** Failed! Falsifiable (after 3 tests): Mix (Mix Red Blue) (Mix Green Red)ghci> hue (Mix magenta yellow)

ghci> quickCheck prop_hue_mix_commutativity+++ OK, passed 100 tests.ghci> quickCheck prop_hue_mix_reflexivity+++ OK, passed 100 tests.ghci> quickCheck prop_hue_bounds*** Failed! Falsifiable (after 3 tests): Mix (Mix Red Blue) (Mix Green Red)ghci> hue (Mix magenta yellow)360.0ghci>

hue (Mix c c') = r where r = case compare d 90 of LT -> m EQ -> nan GT -> m' h = hue c h' = hue c' m = average h h' m' = m + 180 d = distance h m

m'm

hd

h'

hue (Mix c c') = r where r = case compare d 90 of LT -> m EQ -> nan GT -> m' h = hue c h' = hue c' m = average h h' m' = normalize (m + 180) d = distance h m

m'm

hd

h'

hue (Mix c c') = r where r = case compare d 90 of LT -> m EQ -> nan GT -> m' h = hue c h' = hue c' m = average h h' m' = normalize (m + 180) d = distance h m

normalize h | h < 360 = h | otherwise = h - 360

m'm

hd

h'

hue (Mix c c') = r where r = case compare d 90 of LT -> m EQ -> nan GT -> m' h = hue c h' = hue c' m = average h h' m' = normalize (m + 180) d = distance h m

normalize h | h < 360 = h | otherwise = normalize (h - 360)

m'm

hd

h'

hue (Mix c c') = r where r = case compare d 90 of LT -> m EQ -> nan GT -> m' h = hue c h' = hue c' m = average h h' m' = normalize (m + 180) d = distance h m

normalize h | h < 360 = h | otherwise = normalize (h - 360)

m'm

hd

h'ghci>

m'

ghci> quickCheck prop_hue_bounds

m'

ghci> quickCheck prop_hue_bounds+++ OK, passed 100 tests.ghci>

prop_hue_mix_nothing c c' = distance (hue c) (hue c') == 180 ==> isNaN (hue (Mix c c'))

QuickCheck

QuickCheck

prop_hue_mix_nothing c c' = distance (hue c) (hue c') == 180 ==> isNaN (hue (Mix c c'))

ghci> quickCheck prop_hue_mix_nothing

QuickCheck

prop_hue_mix_nothing c c' = distance (hue c) (hue c') == 180 ==> isNaN (hue (Mix c c'))

ghci> quickCheck prop_hue_mix_nothing*** Gave up! Passed only 23 tests.ghci>

QuickCheck

prop_hue_mix_nothing c c' = distance (hue c) (hue c') == 180 ==> isNaN (hue (Mix c c'))

QuickCheck

prop_hue_mix_nothing c c' = distance (hue c) (hue c') == 180 ==> isNaN (hue (Mix c c'))

-- Can we easily find the complement of a color?

complement Red = ???complement Green = ???complement Blue = ???complement (Mix c c') = ???

complement Red = cyancomplement Green = ???complement Blue = ???complement (Mix c c') = ???

complement Red = cyancomplement Green = magentacomplement Blue = ???complement (Mix c c') = ???

complement Red = cyancomplement Green = magentacomplement Blue = yellowcomplement (Mix c c') = ???

complement Red = cyancomplement Green = magentacomplement Blue = yellowcomplement (Mix c c') = Mix ??? ???

complement Red = cyancomplement Green = magentacomplement Blue = yellowcomplement (Mix c c') = Mix (complement c ) (complement c' )

QuickCheck

prop_complement c = let h = hue c in not (isNaN h) ==> distance h (hue (complement c)) == 180

QuickCheck

prop_complement c = let h = hue c in not (isNaN h) ==> distance h (hue (complement c)) == 180

prop_hue_mix_complement c = isNaN (hue (Mix c (complement c)))

QuickCheck

prop_complement c = let h = hue c in not (isNaN h) ==> distance h (hue (complement c)) == 180

prop_hue_mix_complement c = isNaN (hue (Mix c (complement c)))

ghci> quickCheck prop_complement

ghci> quickCheck prop_complement+++ OK, passed 100 tests.ghci>

ghci> quickCheck prop_complement+++ OK, passed 100 tests.ghci> quickCheck prop_hue_mix_complement

ghci> quickCheck prop_complement+++ OK, passed 100 tests.ghci> quickCheck prop_hue_mix_complement+++ OK, passed 100 tests.ghci>

To be continued...

Summary

Haskell is functional.

Haskell has types.

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