This repository has been archived by the owner on Apr 9, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 5
/
Copy pathWeek06Problems.hs
174 lines (129 loc) · 5.11 KB
/
Week06Problems.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
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
module Week06Problems where
{------------------------------------------------------------------------------}
{- TUTORIAL QUESTIONS -}
{------------------------------------------------------------------------------}
data Tree a
= Leaf
| Node (Tree a) a (Tree a)
deriving Show
{- 1. Using 'Result' to handle errors.
Here is the 'Result' type described in the notes. It is like the
'Maybe' type except that the "fail" case has a String message
attached: -}
data Result a
= Ok a
| Error String
deriving (Eq, Show)
{- Implement 'returnOK', 'failure', 'ifOK' and 'catch' for 'Result'
instead of 'Maybe'. Note that in 'failure' we have to provide an
error message, and in 'catch' the "exception handler" gets the
error message. -}
returnOk :: a -> Result a
returnOk = undefined
failure :: String -> Result a
failure = undefined
ifOK :: Result a -> (a -> Result b) -> Result b
ifOK = undefined
catch :: Result a -> (String -> Result a) -> Result a
catch = undefined
{- Reimplement 'search' to use 'Result' instead of 'Maybe'. We add 'Show
k' to the requirements, so that we can put the key that wasn't
found in the error message. -}
search :: (Show k, Eq k) => k -> [(k,v)] -> Result v
search = undefined
{- Finally, reimplement 'lookupAll v4' to return 'Result (Tree v)'
instead of 'Maybe (Tree v)'. (The code will be identical!) -}
lookupAll_v4 :: (Show k, Eq k) => [(k,v)] -> Tree k -> Result (Tree v)
lookupAll_v4 = undefined
{- 2. Processes
The following data type represents processes that can 'Input' lines
and carry on given information about what that line is; 'Output'
lines and then carry on being a process; or 'End', with a value. -}
data Process a
= End a
| Input (String -> Process a)
| Output String (Process a)
{- Here is an example process, written out in full. It implements a
simple interactive program: -}
interaction :: Process ()
interaction =
Output "What is your name?"
(Input (\name ->
Output ("Hello " ++ name ++ "!") (End ())))
{- Processes by themselves do not do anything. They are only
descriptions of what to do. To have an effect on the world, we to
need to translate them to Haskell's primitives for doing I/O (we
will cover this in more detail in Week 08): -}
runProcess :: Process a -> IO a
runProcess (End a) = return a
runProcess (Input k) = do line <- getLine; runProcess (k line)
runProcess (Output line p) = do putStrLn line; runProcess p
{- Now we can run the 'interaction' described above:
> runProcess interaction
What is your name?
Bob <--- this line entered by the user
Hello Bob!
-}
{- Writing out processes in the style of 'interaction' above is annoying
due to the brackets needed. We can make it simpler by defining some
functions, First we define two basic operations: 'input' and
'output', which are little "mini-Processes" that do one input or
output operation. -}
input :: Process String
input = Input (\x -> End x)
output :: String -> Process ()
output s = Output s (End ())
{- The key operation is sequencing of processes. First we (simulate) run
one process, then we take the result value from that and use it to
make a second process which we run. Note that this has the same
flavour as the 'ifOK', 'andThen' and 'andThenWithPrinting'
functions from the notes. -}
sequ :: Process a -> (a -> Process b) -> Process b
sequ (End a) f = undefined
sequ (Input k) f = undefined
sequ (Output s p) f = undefined
{- HINT: this is very very similar to the 'subst' function from Week 03.
Once you have 'subst', you can define a neater version of
'interaction' that makes the sequential nature clearer: -}
interaction_v2 :: Process ()
interaction_v2 =
output "What is your name?" `sequ` \() ->
input `sequ` \name ->
output ("Hello " ++ name ++ "!") `sequ` \() ->
End ()
{- Running 'runProcess interaction_v2' should have the same effect as
running 'runProcess interaction' did.
Let's put sequ to work.
Implement an interactive 'map' using 'input', 'output' and
'sequ'. This is a 'map' that prompts the user for what string to
use to replace each string in the input list. This will be similar
to printAndSum_v2 from the notes.
For example:
> runProcess (interactiveMap ["A","B","C"])
A
a
B
b
C
c
["a","b","c"]
where the lower case lines are entered by the user. -}
interactiveMap :: [String] -> Process [String]
interactiveMap = undefined
{- Finally, implement a function that does an 'interactive filter',
similar to the interactive map. For every element in the input
list, it outputs it and prompts for user input. If the user types
"y" then the element is kept. Otherwise it is not copied into the
output list. -}
interactiveFilter :: Show a => [a] -> Process [a]
interactiveFilter = undefined
{- For example,
> runProcess (interactiveFilter ["A","B","C"])
Keep "A"?
y
Keep "B"?
n
Keep "C"?
y
["A","C"]
-}