Haskell in the Real World

Post on 12-May-2015

2.294 views 0 download

Tags:

description

A short talk on what makes Functional Programming - and especially Haskell - different.We'll take a quick overview of Haskell's features and coding style, and then work through a short but complete example of using it for a Real World problem.http://lanyrd.com/2011/geekup-liverpool-may/sdykh/

Transcript of Haskell in the Real World

Haskell in the Real World

Functional Programming Night

Geekup Liverpool, 31st May, 2011hakim.cassimally@gmail.com

http://www.fickr.com/photos/jef_saf/3493852795/

What makes FP different?

● MJD quoting Norvig (on Lisp):● “big, important features, features like frst-class

functions, dynamic access to the symbol table, and automatic storage management.”

● gluing functions together● declarative

Popular FP languages

● Excel● SQL?● Linq (based on Haskell's monads)● Lisp → Scheme → Clojure● Strongly Typed FP (Hindley/Milner)

● ML → Ocaml → F#● Haskell

What makes Haskell different?

● Purity● Laziness● High Level● Strong Typing● Memory Managed● Modular● Mathematical rigour

● category theory

Sounds a bit ivory tower?

● http://prog21.dadgum.com/31.html

● Q “When will Haskell fnally go mainstream?”

● A “most of it already has.”

Imperative programming● records = [ "one", "two", "three", "four", "five" ]

filtered = []; j = 0;

for (i = 0; i < length records; i++) {

if (records[i] matches “o”) {

filtered[j++] = records[i];}

}

Imperative programming● records = [ "one", "two", "three", "four", "five" ]

filtered = []; j = 0;

for (i = 0; i < length records; i++) {

if (records[i] matches “o”) {

filtered[j++] = records[i];}

}

Functional version

● filtered = filter (=~ “o”) records

Why is this better?

● less code. less bugs● no synthetic variables

● i, j, length records● no risk of off-by-one error● intent clear from skimming● intent clear to compiler● parallelize (MapReduce, Hadoop)

Why is this better?

● fewer codes. fewer bugs● no synthetic variables

● i, j, length records● no risk of off-by-one error● intent clear from skimming● intent clear to compiler● parallelize (MapReduce, Hadoop)

Your language has this construct

● Perl: my @filtered = grep /o/, @records;● .Net: var filtered = from r in records where r.match('o') select r

● Ruby: @filtered = @records.grep /o/● Python: filtered = [x for x in records if re.match('o', x)]

● etc.

Another example

● countCaps = length . filter (isUpper . head) . words

> countCaps “Hello there, Fred” 2

Real World Haskell

● JSON library● barcode reading● database

Quizzes

● important subsystem of Makini's attention management system

● real world (has customers, pays wages)● currently written in Perl● could it be ported to Haskell?

Haskell Quiz – proof of concept

● full code at:● https://github.com/

osfameron/geekup-talk-haskell/

● overview, to give a favour of programming in Haskell

Modelling the quiz

Modelling the quiz

Modelling the quiz

Modelling the quiz

2x

Modelling the quiz

Modelling the quiz

1x

Quiz tree data types

● Quizzes● Sections

● (randomized sections)

● Questions

Quiz data type● data QuizNode = Quiz Name [QuizNode] | Section Name Score [QuizNode] | RandomSection Name Score Choose [QuizNode] | Question Name Score Answer

Quiz data type● data QuizNode = Quiz Name [QuizNode] | Section Name Score [QuizNode] | RandomSection Name Score Choose [QuizNode] | Question Name Score Answer

● type Name = String

type Score = Inttype Choose = Int

Quiz data type● data QuizNode = Quiz Name [QuizNode] | Section Name Score [QuizNode] | RandomSection Name Score Choose [QuizNode] | Question Name Score Answer

● data Answer = MultiChoice [BoolAnswer] | StringChoice [String]

Quiz data type● data QuizNode = Quiz Name [QuizNode] | Section Name Score [QuizNode] | RandomSection Name Score Choose [QuizNode] | Question Name Score Answer

● data Answer = MultiChoice [BoolAnswer] | StringChoice [String]

● data BoolAnswer = BoolAnswer Bool String

Quiz data typequiz,geo,pop :: QuizNodequiz = Quiz “General Knowledge Quiz” [ pop, geo ]

geo = RandomSection “Geography” 40 2 [ Question “What is the capital of England?” 2 $ StringChoice [“London”], Question “What is the capital of France?” 2 $ StringChoice [“Paris”], Question “What is the capital of Finland?” 2 $ StringChoice [“Helsinki”], Question “What is the capital of Italy?” 2 $ StringChoice [“Rome”, “Roma”], ]

Quiz data typequiz,geo,pop :: QuizNodequiz = Quiz “General Knowledge Quiz” [ pop, geo ]

geo = RandomSection “Geography” 40 2 [ Question “What is the capital of England?” 2 $ StringChoice [“London”], Question “What is the capital of France?” 2 $ StringChoice [“Paris”], Question “What is the capital of Finland?” 2 $ StringChoice [“Helsinki”], Question “What is the capital of Italy?” 2 $ StringChoice [“Rome”, “Roma”], ]

Quiz data typequiz,geo,pop :: QuizNodequiz = Quiz “General Knowledge Quiz” [ pop, geo ]

geo = RandomSection “Geography” 40 2 [ Question “What is the capital of England?” 2 $ StringChoice [“London”], Question “What is the capital of France?” 2 $ StringChoice [“Paris”], Question “What is the capital of Finland?” 2 $ StringChoice [“Helsinki”], Question “What is the capital of Italy?” 2 $ StringChoice [“Rome”, “Roma”], ]

Quiz data typepop = Section “Pop music” 60 [ Question “Which of these are Beatles?” 5 $ MultiChoice [ y “John”, y “Paul”, y “George”, y “Ringo”, n “Bob”, n “Jason” ], ...

Quiz data typepop = Section “Pop music” 60 [ Question “Which of these are Beatles?” 5 $ MultiChoice [ BoolAnswer True “John”, BoolAnswer True “Paul”, BoolAnswer True “George”, BoolAnswer True “Ringo”, BoolAnswer False “Bob”, BoolAnswer False “Jason” ], ...

Quiz data typepop = Section “Pop music” 60 [ Question “Which of these are Beatles?” 5 $ MultiChoice [ y “John”, y “Paul”, y “George”, y “Ringo”, n “Bob”, n “Jason” ], ...

y,n :: String -> BoolAnswery = BoolAnswer Truen = BoolAnswer False

Stamping the quiz

1x 2x

Stamping the quiz

1x 2x

Stamping the quiz

1x

stamp :: QuizNode → ...

2x

Stamping the quiz

1x

stamp :: QuizNode → QuizNode?

2x

Functions

● increment :: Num → Num● increment 4 => 5● increment 10 => 11

Functions

● increment :: Num → Num● increment 4 => 5● increment 10 => 11

Functions

● increment :: Num → Num● increment 4 => 5● increment 10 => 11

Functions

● increment :: Num → Num● increment x = x+1

Functions

let x = 42

addx :: Num → Numadd y = x + y

Functions

let x = 42

addx :: Num → Numadd y = x + y

(cannot change!)

Functions

let x = 42

addx :: Num → Numadd y = x + y

Stamping the quiz

1x

stamp :: QuizNode → QuizNode?

2x

Stamping the quiz

1x

stamp :: QuizNode → QuizNode?

2x

Stamping the quiz

1x

stamp :: QuizNode → IO QuizNode

2x

Monads

● Useful data-structure● Lets us model various thing...

● including IO in a pure language● Concept is a little confusing● Using them is (mostly) not too bad.

Stamping the quizstamp :: QuizNode → IO QuizNode

Stamping the quiz

1x 2x

stamp :: QuizNode → IO QuizNode

Stamping the quiz

1x 2x

stamp :: QuizNode → IO QuizNode

Stamping the quizstamp :: QuizNode → IO QuizNode

Stamping the quizstamp :: QuizNode → IO QuizNode

The stamp function

stamp :: QuizNode -> IO QuizNode

stamp q@(Question _ _ _) = return q

stamp (Quiz s ns) = Quiz s <$> mapM stamp nsstamp (Section s i ns) = Section s i <$> mapM stamp ns

stamp (RandomSection s i r ns) = do selected <- pickN r ns Section s i <$> mapM stamp selected

The stamp function

stamp :: QuizNode -> IO QuizNode

stamp q@(Question _ _ _) = return q

stamp (Quiz s ns) = Quiz s <$> mapM stamp nsstamp (Section s i ns) = Section s i <$> mapM stamp ns

stamp (RandomSection s i r ns) = do selected <- pickN r ns Section s i <$> mapM stamp selected

The stamp function

stamp :: QuizNode -> IO QuizNode

stamp q@(Question _ _ _) = return q

stamp (Quiz s ns) = Quiz s <$> mapM stamp nsstamp (Section s i ns) = Section s i <$> mapM stamp ns

stamp (RandomSection s i r ns) = do selected <- pickN r ns Section s i <$> mapM stamp selected

map stamp ns– “stamp all the child nodes in turn”

The stamp function

stamp :: QuizNode -> IO QuizNode

stamp q@(Question _ _ _) = return q

stamp (Quiz s ns) = Quiz s <$> mapM stamp nsstamp (Section s i ns) = Section s i <$> mapM stamp ns

stamp (RandomSection s i r ns) = do selected <- pickN r ns Section s i <$> mapM stamp selected

The stamp function

stamp :: QuizNode -> IO QuizNode

stamp q@(Question _ _ _) = return q

stamp (Quiz s ns) = Quiz s <$> mapM stamp nsstamp (Section s i ns) = Section s i <$> mapM stamp ns

stamp (RandomSection s i r ns) = do selected <- pickN r ns Section s i <$> mapM stamp selected

1x

Taking the quiz!

● takeNode :: QuizNode -> IO CompletedNode

● printQuestion :: QuizNode -> IO ()

● showBoolTextAnswers :: [BoolAnswer] -> String

● checkAnswer :: String -> Answer -> Bool

Taking the quiz!

● takeNode :: QuizNode -> IO CompletedNode

● printQuestion :: QuizNode -> IO ()

● showBoolTextAnswers :: [BoolAnswer] -> String

● checkAnswer :: String -> Answer -> Bool

Taking the quiz!

● takeNode :: QuizNode -> IO CompletedNode

● printQuestion :: QuizNode -> IO ()

● showBoolTextAnswers :: [BoolAnswer] -> String

● checkAnswer :: String -> Answer -> Bool

Taking the quiz!

● takeNode :: QuizNode -> IO CompletedNode

● printQuestion :: QuizNode -> IO ()

● showBoolTextAnswers :: [BoolAnswer] -> String

● checkAnswer :: String -> Answer -> Bool

takeNode

takeNode node@(Question s i a) = do printQuestion node ans <- getLine let correct = checkAnswer ans a let score = if correct

then (i,i) else (0,i) putStrLn $ if correct

then “Correct!” else “Wrong!” return $

CompletedNode ans score [] node

main

main :: IO ()main = stamp quiz >>= takeQuiz

Function, not entrypoint

main

main :: IO ()main = stamp quiz >>= takeQuiz

Live Demo!

Should you go Haskell?

● Power● Speed?

● can be faster than C (supercompilation)● can be tricky to optimize

● Jobs?● In NorthWestUK?

● Libraries & Tools● Haskell Platform. Hackage. Cabal

Should you learn Haskell?

● Powerful● Interesting techniques● … and ways of thinking about problems● Ready for future shift to FP● … possibly in your own language

Thank you! Questions?

● full code at:● https://github.com/

osfameron/geekup-talk-haskell/

● hakim.cassimally@gmail.com

http://www.fickr.com/photos/jef_saf/3493852795/