forked from charleso/introduction-to-fp-in-scala
-
Notifications
You must be signed in to change notification settings - Fork 2
/
Http.scala
171 lines (150 loc) · 3.71 KB
/
Http.scala
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
package patterns
import intro._ // type classes
/*
* A http datatype that represents a number of read/write/state/result
* like structure as a function.
*/
case class Http[A](run: (HttpRead, HttpState) => (HttpWrite, HttpState, HttpValue[A])) {
/*
* Exercise 8a.1:
*
* Implement map for Http[A].
*
* The following laws must hold:
* 1) r.map(z => z) == r
* 2) r.map(z => f(g(z))) == r.map(g).map(f)
*/
def map[B](f: A => B): Http[B] =
???
/*
* Exercise 8a.2:
*
* Implement flatMap (a.k.a. bind, a.k.a. >>=).
*
* The following law must hold:
* r.flatMap(f).flatMap(g) == r.flatMap(z => f(z).flatMap(g))
*
*/
def flatMap[B](f: A => Http[B]): Http[B] =
???
}
object Http {
/*
* Exercise 8a.3:
*
* Implement value (a.k.a. return, point, pure).
*
* Hint: Try using Http constructor.
*/
def value[A](a: => A): Http[A] =
???
/*
* Exercise 8a.4:
*
* Implement ask for Http, similar behaviour to Reader.ask.
*
* Hint: Try using Http constructor.
*/
def httpAsk: Http[HttpRead] =
???
/*
* Exercise 8a.5:
*
* Implement get for Http, similar behaviour to State.get.
*
* Hint: Try using Http constructor.
*/
def httpGet: Http[HttpState] =
???
/*
* Exercise 8a.6:
*
* Implement modify for Http, similar behaviour to State.modify.
*
* Hint: Try using Http constructor.
*/
def httpModify(f: HttpState => HttpState): Http[Unit] =
???
/*
* Exercise 8a.7:
*
* Implement getBody.
*
* Hint: You may want to define some other combinators to help
* that have not been specified yet, remember exercise 2 ask?
*/
def getBody: Http[String] =
???
/*
* Exercise 8a.8:
*
* Implement addHeader.
*
* Hint: You may want to define some other combinators to help
* that have not been specified yet, remember exercise 4 update?
*/
def addHeader(name: String, value: String): Http[Unit] =
???
/*
* Exercise 8a.9:
*
* Implement log.
*
* Hint: Try using Http constructor.
*/
def log(message: String): Http[Unit] =
???
implicit def HttpMonad: Monad[Http] =
new Monad[Http] {
def point[A](a: => A) = Http.value(a)
def bind[A, B](a: Http[A])(f: A => Http[B]) = a flatMap f
}
}
object HttpExample {
import Http._
/*
* Exercise 8a.10:
*
* Implement echo http service.
*
* Echo service should:
* return body as string,
* add "content-type" header of "text/plain"
* log a message with the length of the body in characters.
*
* Hint: Try using flatMap or for comprehensions.
*/
def echo: Http[String] =
???
}
/** Data type wrapping up all http state data */
case class HttpState(resheaders: Headers)
/** Data type wrapping up all http environment data */
case class HttpRead(method: Method, body: String, reqheaders: Headers)
/** Data type wrapping up http log data */
case class HttpWrite(log: Vector[String]) {
def ++(w: HttpWrite) =
HttpWrite(log ++ w.log)
}
/** Monoid for HttpWrite (for completeness and convenience). */
object HttpWrite {
implicit def HttpWriteMonoid: Monoid[HttpWrite] = new Monoid[HttpWrite] {
def identity = HttpWrite(Vector())
def op(a: HttpWrite, b: HttpWrite) = a ++ b
}
}
/** Headers data type. */
case class Headers(headers: Vector[(String, String)] = Vector()) {
def :+(p: (String, String)) =
Headers(headers :+ p)
}
/** Method data type. */
sealed trait Method
case object Options extends Method
case object Get extends Method
case object Head extends Method
case object Post extends Method
case object Put extends Method
case object Delete extends Method
case object Trace extends Method
case object Connect extends Method