Haskell in the Real World



       Functional Programming Night
               Geekup Liverpool, 31st May, 2011
                hakim.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 = Int
    type 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 type
quiz,geo,pop :: QuizNode
quiz = 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 type
quiz,geo,pop :: QuizNode
quiz = 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 type
quiz,geo,pop :: QuizNode
quiz = 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 type
pop = 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 type
pop = 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 type
pop = 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 -> BoolAnswer
y = BoolAnswer True
n = BoolAnswer False
Stamping the quiz


1x        2x
Stamping the quiz


1x        2x
Stamping the quiz
         stamp ::
           QuizNode → ...

1x        2x
Stamping the quiz
         stamp ::
           QuizNode → QuizNode?

1x        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 → Num
   add y = x + y
Functions

           (cannot
let x = 42 change!)




    addx :: Num → Num
    add y = x + y
Functions

let x = 42




   addx :: Num → Num
   add y = x + y
Stamping the quiz
         stamp ::
           QuizNode → QuizNode?

1x        2x
Stamping the quiz
         stamp ::
           QuizNode → QuizNode?

1x        2x
Stamping the quiz
         stamp ::
           QuizNode → IO QuizNode

1x        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 quiz
    stamp ::
      QuizNode → IO QuizNode
Stamping the quiz
         stamp ::
           QuizNode → IO QuizNode

1x        2x
Stamping the quiz
         stamp ::
           QuizNode → IO QuizNode

1x        2x
Stamping the quiz
    stamp ::
      QuizNode → IO QuizNode
Stamping the quiz
    stamp ::
      QuizNode → IO QuizNode
The stamp function
stamp :: QuizNode -> IO QuizNode

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

stamp (Quiz s ns)      = Quiz    s   <$> mapM stamp ns
stamp (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 ns
stamp (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
                                       map stamp ns
stamp :: QuizNode -> IO QuizNode       – “stamp all the
                                       child nodes in
stamp q@(Question _ _ _) = return q    turn”
stamp (Quiz s ns)      = Quiz    s   <$> mapM stamp ns
stamp (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 ns
stamp (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 ns
stamp (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/

Haskell in the Real World

  • 1.
    Haskell in theReal World Functional Programming Night Geekup Liverpool, 31st May, 2011 hakim.cassimally@gmail.com http://www.fickr.com/photos/jef_saf/3493852795/
  • 2.
    What makes FPdifferent? ● 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
  • 3.
    Popular FP languages ● Excel ● SQL? ● Linq (based on Haskell's monads) ● Lisp → Scheme → Clojure ● Strongly Typed FP (Hindley/Milner) ● ML → Ocaml → F# ● Haskell
  • 4.
    What makes Haskelldifferent? ● Purity ● Laziness ● High Level ● Strong Typing ● Memory Managed ● Modular ● Mathematical rigour ● category theory
  • 5.
    Sounds a bitivory tower? ● http://prog21.dadgum.com/31.html ● Q “When will Haskell fnally go mainstream?” ● A “most of it already has.”
  • 6.
    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]; } }
  • 7.
    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]; } }
  • 8.
    Functional version ● filtered = filter (=~ “o”) records
  • 9.
    Why is thisbetter? ● 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)
  • 10.
    Why is thisbetter? ● 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)
  • 11.
    Your language hasthis 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.
  • 12.
    Another example ● countCaps = length . filter (isUpper . head) . words > countCaps “Hello there, Fred” 2
  • 13.
    Real World Haskell ● JSON library ● barcode reading ● database
  • 14.
    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?
  • 15.
    Haskell Quiz –proof of concept ● full code at: ● https://github.com/ osfameron/geekup-talk-haskell/ ● overview, to give a favour of programming in Haskell
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
    Quiz tree datatypes ● Quizzes ● Sections ● (randomized sections) ● Questions
  • 23.
    Quiz data type ● data QuizNode = Quiz Name [QuizNode] | Section Name Score [QuizNode] | RandomSection Name Score Choose [QuizNode] | Question Name Score Answer
  • 24.
    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 = Int type Choose = Int
  • 25.
    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]
  • 26.
    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
  • 27.
    Quiz data type quiz,geo,pop:: QuizNode quiz = 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”], ]
  • 28.
    Quiz data type quiz,geo,pop:: QuizNode quiz = 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”], ]
  • 29.
    Quiz data type quiz,geo,pop:: QuizNode quiz = 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”], ]
  • 30.
    Quiz data type pop= Section “Pop music” 60 [ Question “Which of these are Beatles?” 5 $ MultiChoice [ y “John”, y “Paul”, y “George”, y “Ringo”, n “Bob”, n “Jason” ], ...
  • 31.
    Quiz data type pop= 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” ], ...
  • 32.
    Quiz data type pop= 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 -> BoolAnswer y = BoolAnswer True n = BoolAnswer False
  • 33.
  • 34.
  • 35.
    Stamping the quiz stamp :: QuizNode → ... 1x 2x
  • 36.
    Stamping the quiz stamp :: QuizNode → QuizNode? 1x 2x
  • 37.
    Functions ● increment :: Num → Num ● increment 4 => 5 ● increment 10 => 11
  • 38.
    Functions ● increment :: Num → Num ● increment 4 => 5 ● increment 10 => 11
  • 39.
    Functions ● increment :: Num → Num ● increment 4 => 5 ● increment 10 => 11
  • 40.
    Functions ● increment :: Num → Num ● increment x = x+1
  • 41.
    Functions let x =42 addx :: Num → Num add y = x + y
  • 42.
    Functions (cannot let x = 42 change!) addx :: Num → Num add y = x + y
  • 43.
    Functions let x =42 addx :: Num → Num add y = x + y
  • 44.
    Stamping the quiz stamp :: QuizNode → QuizNode? 1x 2x
  • 45.
    Stamping the quiz stamp :: QuizNode → QuizNode? 1x 2x
  • 46.
    Stamping the quiz stamp :: QuizNode → IO QuizNode 1x 2x
  • 47.
    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.
  • 48.
    Stamping the quiz stamp :: QuizNode → IO QuizNode
  • 49.
    Stamping the quiz stamp :: QuizNode → IO QuizNode 1x 2x
  • 50.
    Stamping the quiz stamp :: QuizNode → IO QuizNode 1x 2x
  • 51.
    Stamping the quiz stamp :: QuizNode → IO QuizNode
  • 52.
    Stamping the quiz stamp :: QuizNode → IO QuizNode
  • 53.
    The stamp function stamp:: QuizNode -> IO QuizNode stamp q@(Question _ _ _) = return q stamp (Quiz s ns) = Quiz s <$> mapM stamp ns stamp (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
  • 54.
    The stamp function stamp:: QuizNode -> IO QuizNode stamp q@(Question _ _ _) = return q stamp (Quiz s ns) = Quiz s <$> mapM stamp ns stamp (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
  • 55.
    The stamp function map stamp ns stamp :: QuizNode -> IO QuizNode – “stamp all the child nodes in stamp q@(Question _ _ _) = return q turn” stamp (Quiz s ns) = Quiz s <$> mapM stamp ns stamp (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
  • 56.
    The stamp function stamp:: QuizNode -> IO QuizNode stamp q@(Question _ _ _) = return q stamp (Quiz s ns) = Quiz s <$> mapM stamp ns stamp (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
  • 57.
    The stamp function stamp:: QuizNode -> IO QuizNode stamp q@(Question _ _ _) = return q stamp (Quiz s ns) = Quiz s <$> mapM stamp ns stamp (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
  • 58.
    Taking the quiz! ● takeNode :: QuizNode -> IO CompletedNode ● printQuestion :: QuizNode -> IO () ● showBoolTextAnswers :: [BoolAnswer] -> String ● checkAnswer :: String -> Answer -> Bool
  • 59.
    Taking the quiz! ● takeNode :: QuizNode -> IO CompletedNode ● printQuestion :: QuizNode -> IO () ● showBoolTextAnswers :: [BoolAnswer] -> String ● checkAnswer :: String -> Answer -> Bool
  • 60.
    Taking the quiz! ● takeNode :: QuizNode -> IO CompletedNode ● printQuestion :: QuizNode -> IO () ● showBoolTextAnswers :: [BoolAnswer] -> String ● checkAnswer :: String -> Answer -> Bool
  • 61.
    Taking the quiz! ● takeNode :: QuizNode -> IO CompletedNode ● printQuestion :: QuizNode -> IO () ● showBoolTextAnswers :: [BoolAnswer] -> String ● checkAnswer :: String -> Answer -> Bool
  • 62.
    takeNode takeNode node@(Question si 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
  • 63.
    main main :: IO() main = stamp quiz >>= takeQuiz Function, not entrypoint
  • 64.
    main main :: IO() main = stamp quiz >>= takeQuiz Live Demo!
  • 65.
    Should you goHaskell? ● Power ● Speed? ● can be faster than C (supercompilation) ● can be tricky to optimize ● Jobs? ● In NorthWestUK? ● Libraries & Tools ● Haskell Platform. Hackage. Cabal
  • 66.
    Should you learnHaskell? ● Powerful ● Interesting techniques ● … and ways of thinking about problems ● Ready for future shift to FP ● … possibly in your own language
  • 67.
    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/