-
Notifications
You must be signed in to change notification settings - Fork 3
/
Step_2_6.hs
104 lines (72 loc) · 3.13 KB
/
Step_2_6.hs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
module Step_2_6 where
import Text.Html
page = thehtml <<
[ header << (thetitle << "Output")
, body <<
[ h1 << "A to-do list:"
, thediv << toDoHtml
, h1 << "Some action:"
, thediv << comicAction
]
]
-- Here's a version of renderToDo written with patterns.
-- Getting simpler, isn't it?
toDoItems :: [String] -- a list of strings
toDoItems = ["Pick up avocados", "Make snacks", "Clean house", "Have party"]
renderToDo :: [String] -> [Html]
renderToDo [] = []
renderToDo (t:ts) = li << t : renderToDo ts
toDoHtml :: Html
toDoHtml = ulist << renderToDo toDoItems
-- Here's another kind of list
comicbookWords :: [String]
comicbookWords = ["Pow", "Blamo", "Zap"]
comicStyle :: String -> Html
comicStyle word = paragraph << bold << ("** " ++ word ++ "! **")
renderAction :: [String] -> [Html]
renderAction [] = []
renderAction (w:ws) = comicStyle w : renderAction ws
comicAction :: Html
comicAction = blockquote << renderAction comicbookWords
-- Look carefully at renderAction and renderToDo. Do they look similar?
-- Each is applying some operation to the first element of the list, and
-- constructing a list from the result and a recursive call over the remainder
-- of the list. When there are no more elements, they return an empty list.
-- Haskellers hate repeating themselves!
-- This pattern is so common there a higher-order function to do this: map
renderToDo' :: [String] -> [Html]
renderToDo' ts = map (li <<) ts
renderAction' :: [String] -> [Html]
renderAction' ws = map comicStyle ws
-- Try changing toDoHtml and comicAction to use these versions and see that they
-- work the same.
-- Oh yeah, we slipped in two more things about Haskell there.
-- 1) You can use ' as a character in names
-- 2) (li <<) is a handy shortcut. It makes a function that takes an argument
-- and applies to the empty side of the operator. You can do this with any
-- operator(*):
addTwo = (+ 2)
dividedByTwo = (/ 2)
twoOver = (2 /)
putStarsInFront = ("**" ++)
putStarsAtEnd = (++ "**")
-- map is so useful, and makes your code very short. Even more amazing is that
-- there nothing special about the implementation of map. In fact you can easily
-- make your own!
-- The hardest part of myMap is the type signature, so we'll give you that:
myMap :: (a -> b) -> [a] -> [b]
-- Let's break this down:
-- (a -> b) -- the first argument is a function! this function takes any type
-- of argument, let's call it a, and produces some type of result,
-- let's call it b
-- -> [a] -- the second argument to map is a list of somethings, and they'd
-- better be the same type as the argument to the function argument
-- -> [b] -- the result is a list of somethings, and they'll be the same type
-- as the function's result
-- Notice that the type signature didn't care about particular types, so it used
-- type variables to talk about them.
-- Now, here's the first clause of myMay. You can write the other:
myMap f [] = []
-- Replace map in the above functions with myMap and see that it works.
--------------
-- (*) Except - ! You can't because (-3) means negative 3.