From 93c8ae77b8dab842e074dd0e1ea2f1bccb1401f5 Mon Sep 17 00:00:00 2001 From: Mark Lentczner Date: Fri, 11 Feb 2011 23:54:44 -0800 Subject: [PATCH] added some more to Chapter3 --- seed/Chapter3/Step_3_4.hs | 2 +- seed/Chapter3/Step_3_5.hs | 57 ++++++++++++++++++++++++++ seed/Chapter3/Step_3_6.hs | 59 +++++++++++++++++++++++++++ seed/Chapter3/Step_3_7.hs | 86 +++++++++++++++++++++++++++++++++++++++ seed/lib/Tutorial.hs | 3 ++ 5 files changed, 206 insertions(+), 1 deletion(-) create mode 100644 seed/Chapter3/Step_3_5.hs create mode 100644 seed/Chapter3/Step_3_6.hs create mode 100644 seed/Chapter3/Step_3_7.hs diff --git a/seed/Chapter3/Step_3_4.hs b/seed/Chapter3/Step_3_4.hs index a660838..2b258de 100644 --- a/seed/Chapter3/Step_3_4.hs +++ b/seed/Chapter3/Step_3_4.hs @@ -10,7 +10,7 @@ page = thehtml << ] ] --- Rewrite all of this to use a type synonym. +-- Rewrite all of this to use a type synonym for the tuple. toDoItems :: [(Bool, String)] -- a list of tuples: each a Bool and String toDoItems = diff --git a/seed/Chapter3/Step_3_5.hs b/seed/Chapter3/Step_3_5.hs new file mode 100644 index 0000000..a503f06 --- /dev/null +++ b/seed/Chapter3/Step_3_5.hs @@ -0,0 +1,57 @@ +module Step_3_5 where + +import Slides + +page = slideDeck "Chapter 3" + [ codeSlide "Not that safe" + "Type synonyms are quick and easy and often the right choice, but \ + \don't offer as much type saftey as possible. Consider:" + [ "type Range = (Int, Int)" + , "inRange :: Range -> Int -> Bool" + , "inRange (lo,hi) x = lo <= x && x <= hi" + , "" + , "type Point = (Int, Int)" + , "p :: Point" + , "p = (3,7)" + , "" + , "ick = inRange p 4 -- compiles!" + ] + , codeSlide "Data Types" + "Data types let you create a type that is distinct. When you so you \ + \define a constructor that builds values of the type:" + [ "data Range = Range Int Int" + , "inRange :: Range -> Int -> Bool" + , "inRange (Range lo hi) x = lo <= x && x <= hi" + , "" + , "data Point = Point Int Int" + , "p :: Point" + , "p = Point 3 7" + , "" + , "ick = inRange p 4 -- now this is a compile error" + ] + , codeSlide "Multiple Constrcutors" + "Data types are very powerful. They can have more than one constructor \ + \and each constructor can have any number of values:" + [ "data Direction = North | East | South | West" + , " deriving (Eq, Show)" + , "" + , "data Weather = Sunny | Rainy Double | Windy Double Direction" + , "describe :: Weather -> String" + , "describe Sunny = \"lovely\"" + , "describe (Rainy inches) | inches < 0.2 = \"drizzle\"" + , " | otherwise = \"wet\"" + , "describe (Windy speed dir) = " + , " \"blowin' \" ++ show speed ++ \" from \" ++ show dir" + ] + , codeSlide "Wait, Deriving What?" + "The deriving clause on the data declaration is a bit of boilerplate \ + \saver that will make your data do more. Here are some of the things \ + \you can 'derive' for your data automatically:" + [ "Eq -- works with == and /= operators" + , "Ord -- works with <, >, etc.." + , "Show -- works with show" + , "Read -- works with read" + , "Enum -- convertable to/from integers" + , "Bounded -- has a min and max value" + ] + ] \ No newline at end of file diff --git a/seed/Chapter3/Step_3_6.hs b/seed/Chapter3/Step_3_6.hs new file mode 100644 index 0000000..282d047 --- /dev/null +++ b/seed/Chapter3/Step_3_6.hs @@ -0,0 +1,59 @@ +module Step_3_6 where + +import Text.Html + +page = thehtml << + [ header << (thetitle << "Output") + , body << + [ h1 << "A to do list:" + , thediv << toDoHtml + , h1 << "# people invited:" + , p << show (headcount invited) + ] + ] + +-- We've written two lists. + +data ToDo = ToDo String | Done String + +toDoItems :: [ToDo] +toDoItems = + [ Done "Pick up avacados" + , Done "Make snacks" + , ToDo "Clean house" + , ToDo "Have party" + ] + + +data Invite = Invite String Int + +who :: Invite -> String +who (Invite name count) = name + +invited :: [Invite] +invited = + [ Invite "Amy" 1 + , Invite "Bob" 7 -- he's got lots of kids + , Invite "Cam" 2 + , Invite "Doris" 3 + , Invite "Edgar" 2 + , Invite "Fran" 2 + ] + +formatToDo :: ToDo -> Html +-- Try writing this + +renderToDo :: [ToDo] -> [Html] +renderToDo ts = map formatToDo ts + +toDoHtml :: Html +toDoHtml = ulist << renderToDo toDoItems + +-- NEXT + +-- Write this function + +headcount :: [Invite] -> Int +headcount is = 0 -- this list was just a place holder, delete it + + diff --git a/seed/Chapter3/Step_3_7.hs b/seed/Chapter3/Step_3_7.hs new file mode 100644 index 0000000..c54131e --- /dev/null +++ b/seed/Chapter3/Step_3_7.hs @@ -0,0 +1,86 @@ +module Step_3_7 where + +import Text.Html + +page = thehtml << + [ header << (thetitle << "Output") + , body << + [ h1 << "A to do list:" + , thediv << toDoHtml + , reminderHtml + , h1 << "# people invited:" + , p << show (headcount invited) + ] + ] + +data ToDo = ToDo String | Done String + +toDoItems :: [ToDo] +toDoItems = + [ Done "Pick up avacados" + , Done "Make snacks" + , ToDo "Clean house" + , ToDo "Have party" + ] + +-- We need a function to return the next item to do. +-- Something like: +-- whatToDoNext :: [ToDo] -> ToDo + +-- But what should it return if they are all done? +-- Enter Maybe: +whatToDoNext :: [ToDo] -> Maybe String + +-- The return type is Maybe String -- in the same way [String] is a type 'built' +-- from the String type, Maybe String is a type 'built' from the String type. But +-- rather than a list, values of type Maybe String can have one of two forms: +-- Just someString +-- Nothing +whatToDoNext (Done item : ts) = whatToDoNext ts +whatToDoNext (ToDo item : ts) = Just item +whatToDoNext [] = Nothing + +formatNotice :: Maybe String -> Html +formatNotice Nothing = noHtml +formatNotice (Just item) = h1 << ("*** DO THIS: " ++ item ++ " ***") + +reminderHtml :: Html +reminderHtml = formatNotice $ whatToDoNext toDoItems + + +formatToDo :: ToDo -> Html +formatToDo (ToDo item) = li << bold << item +formatToDo (Done item) = li << item + +renderToDo :: [ToDo] -> [Html] +renderToDo ts = map formatToDo ts + +toDoHtml :: Html +toDoHtml = ulist << renderToDo toDoItems + +-- Try changing the toDoItems to be all Done and see how this works + + +-- NEXT +-- Add an optional partner or spouse to the invite data type. +-- Add a list of invitiees (and optional partners!) to the page. + +data Invite = Invite String Int + +who :: Invite -> String +who (Invite name count) = name + +invited :: [Invite] +invited = + [ Invite "Amy" 1 + , Invite "Bob" 7 -- he's got lots of kids + , Invite "Cam" 2 + , Invite "Doris" 3 + , Invite "Edgar" 2 + , Invite "Fran" 2 + ] + +headcount :: [Invite] -> Int +headcount [] = 0 +headcount (Invite who count : is) = count + headcount is + diff --git a/seed/lib/Tutorial.hs b/seed/lib/Tutorial.hs index 865ec87..9185085 100644 --- a/seed/lib/Tutorial.hs +++ b/seed/lib/Tutorial.hs @@ -69,6 +69,9 @@ steps = , Step 3 2 Code , Step 3 3 Slides , Step 3 4 Code + , Step 3 5 Slides + , Step 3 6 Code + , Step 3 7 Code ] stepUrls :: [String]