packages feed

barley-0.3: seed/Chapter2/Step_2_4.hs

module Step_2_4 where

import Slides

page = slideDeck "Chapter 2: Lists"
    [ titleSlide "All About Lists"
        [ ]
    , codeSlide "Making Lists"
        "Up to now we've been making lists using this syntax:"
        [ "[]        -- the empty list"
        , "[42]      -- a list of one value"
        , "[1, 2, 3] -- a list of three values"
        ]
    , pointSlide "The Truth About Lists"
        "Lists in Haskell are actually linked lists, not arrays, and are \
        \built recursively. A list is always just one of these two forms:"
        [ "The empty list"
        , "The first item in the list, and the rest of the list"
        ]
    , codeSlide "Lists in Haskell"
        "In Haskell, [] is the empty list, and the : operator is used to build\
         \up lists:"
        [ "[]             -- the empty list"
        , "42 : []        -- a list of one value"
        , "1 : 2 : 3 : [] -- a list of three values"
        ]
    , codeSlide "Lists in Lisps"
        "In various Lisp dialects, this would look like:"
        [ "nil                           -- the empty list"
        , "(cons 42 nil)                 -- a list of one value"
        , "(cons 1 (cons 2 (cons 3 []))) -- a list of three values"
        ]
    , codeSlide "Watch out: Haskell's : ≠ Lisp's cons"
        "In Lisp, cons puts any two things together. Not so in Haskell. In \
        \Haskell : always takes an element on the left and a (possibly empty) \
        \list on the right:"
        [ "(cons 42 109)  -- legal in Lisp"
        , "42 : 109       -- NOT legal in Haskell"
        ]
    , codeSlide "Watch out: Haskell's Lists must be homogeneous"
        "In many languages list elements can be different types. Not so in \
        \Haskell. In Haskell all elements of the list must be the same type."
        [ "[2, \"bob\"]          -- legal in Python, Javascript, etc.."
        , "[2, \"bob\"]          -- NOT legal in Haskell"
        , "[[1,2,3], [10,20,30]] -- of course lists of lists are fine!"
        ]
    , codeSlide "Syntatic Sugar"
        "In Haskell, the way we've been writing lists is just syntatic sugar \
        \for their construction with the : operator and []:"
        [ "[42]      == 42 : []"
        , "[1, 2, 3] ==  1 : 2 : 3 : []"
        ]
    , codeSlide "Watch out: Using the right form"
        "It is easy get tripped up with the sugar. Make sure you see how these \
        \pairs of expressions are the same work:"
        [ "[1]   ==  1  : []"
        , "[[1]] == [1] : []"
        , "[1]   == [1] ++ []"
        , "[1, 2]   ==  1  : [2]  ==  1 : 2 : []"
        , ""
        , "1 ++ []  -- illegal, needs a list on both sides to concatenate"
        , "[1] : 2  -- illegal, needs a list on the right"
        , "[] : []  -- legal, but what is it?"
        , "-- remember: list on the left of a : implies list of lists..."
        ]
    , codeSlide "Inspecting Lists"
       "When working with lists, so far we've used functions and guards. \
       \Consider:"
       [ "showFirstNumber :: [Int] -> String"
       , "showFirstNumber is ="
       , "    | is == [] = \"No first number.\""
       , "    | otherwise = \"The first number is \" ++ show (head is) ++ \".\""
       ]
    , codeSlide "Inspecting Lists"
       "Instead, since there are just two forms of list, and those are exactly \
       \what this function is looking for, we can pattern match for them:"
       [ "showFirstNumber :: [Int] -> String"
       , "showFirstNumber []     = \"No first number.\""
       , "showFirstNumber (i:is) = \"The first number is \" ++ show i ++ \".\""
       ]
    , pointSlide "How's That Work?"
       "Haskell will pick the first 'equation' for a function where the \
       \arguments match the given pattern:"
       [ "[] will match only the empty list"
       , "(i:is) will match a list that has a first item (i) and a rest of the \
           \list (is). Careful: Notice that those are parenthesis, not square \
           \brackets around the : expression!"
       ]
    , codeSlide "Some gotchas:"
       "Look at this function to see how NOT to get caught up between matching \
       \the : operator, vs. matching the syntatic sugar lists:"
       [ "funnyFunction :: [Int] -> String"
       , "funnyFunction [] = \"Empty List\""
       , "funnyFunction [i] = \"One element list\""
       , "funnyFunction (i:is) = \"List with at least one element\""
       , "funnyFunction [i,j] = \"Two element list\""
       , "  -- would never match because the clause above matches two element lists as well!"
       , "funnyFunction [i:is] = \"A list with one element that is at least a one element list\""
       , "  -- the last one won't compile because it doesn't match the type of the argument"
       ]
    , pointSlide "Patterns Ahoy!"
       "Using pattern matching is generally more concise and clear (once you \
       \get used to it)."
       [ "Be brave!"
       , "We'll write with patterns from now on where we can."
       ]
    , codeSlide "One more thing..."
       "String is just a list of Char, or technically [Char]. Which means all \
       \the list functions and list patterns work on Strings. Woot!  These are \
       \all the same:"
       [ "\"abc\""
       , "['a', 'b', 'c']"
       , "'a' : 'b' : 'c' : []"
       ]
    ]