haskell in the real world
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
Haskell in the Real World
Functional Programming Night
Geekup Liverpool, 31st May, [email protected]
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/
http://www.fickr.com/photos/jef_saf/3493852795/