forked from markhibberd/introduction-to-fp-in-scala
-
Notifications
You must be signed in to change notification settings - Fork 5
/
Reader.scala
145 lines (127 loc) · 3.38 KB
/
Reader.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
package patterns
import intro._
/*
* A reader data type that represents the application of some
* environment to produce a value.
*/
case class Reader[R, A](run: R => A) {
/*
* Exercise 2.1:
*
* Implement map for Reader[R, A].
*
* The following laws must hold:
* 1) r.map(z => z) == r
* 2) r.map(z => f(g(z))) == r.map(g).map(f)
*
* Two readers are equal if for all inputs, the same result is produced.
*/
def map[B](f: A => B): Reader[R, B] =
???
/*
* Exercise 2.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))
*
* Two readers are equal if for all inputs, the same result is produced.
*/
def flatMap[B](f: A => Reader[R, B]): Reader[R, B] =
???
}
object Reader {
/*
* Exercise 2.3:
*
* Implement value (a.k.a. return, point, pure).
*
* Hint: Try using Reader constructor.
*/
def value[R, A](a: => A): Reader[R, A] =
???
/*
* Exercise 2.4:
*
* Implement ask.
*
* Ask provides access to the current environment (R).
*
* Hint: Try using Reader constructor.
*/
def ask[R]: Reader[R, R] =
???
/*
* Exercise 2.5:
*
* Implement local.
*
* Local produce a reader that runs with a modified environment.
*
* Hint: Try using Reader constructor.
*/
def local[R, A](f: R => R)(reader: Reader[R, A]): Reader[R, A] =
???
/*
* Exercise 2.6:
*
* Sequence, a list of Readers, to a Reader of Lists.
*/
def sequence[R, A](readers: List[Reader[R, A]]): Reader[R, List[A]] =
???
implicit def ReaderMonoid[R, A: Monoid]: Monoid[Reader[R, A]] =
new Monoid[Reader[R, A]] {
def identity: Reader[R, A] =
value[R, A](Monoid[A].identity)
def op(a: Reader[R, A], b: Reader[R, A]): Reader[R, A] =
for { aa <- a; bb <- b } yield Monoid[A].op(aa, bb)
}
class Reader_[R] {
type l[a] = Reader[R, a]
}
implicit def ReaderMonad[R]: Monad[Reader[R, ?]] =
new Monad[Reader[R, ?]] {
def point[A](a: => A): Reader[R, A] =
value(a)
def bind[A, B](r: Reader[R, A])(f: A => Reader[R, B]): Reader[R, B] =
r flatMap f
}
}
/*
* *Challenge* Exercise 2.7: Indirection.
*
* Lookup a specified config value, and then use its values
* as keys to look up a subsequent set of values.
*
* Complete the implementation, some of the methods are provided
* fill in the remainder, to complete the spec.
*/
object Example {
case class ConfigEntry(name: String, values: List[String])
case class Config(data: List[ConfigEntry])
/*
* For a single name, lookup all of the direct values for that name.
*
* Libraries available:
* - The Reader.* libraries
* - List[A] has `find` method that will provide a Option[A]
* - Option[A] has a `getOrElse` method similar to challenge1.Result
*
* Hint: Starting with Reader.ask will help.
*/
def direct(name: String): Reader[Config, List[String]] =
???
/*
* For a single name, lookup all of the indirect values, that
* is those values whose key is a one of the direct values of
* the specified name.
*
* Libraries available:
* - List[List[A]].flatten will produce a List[A].
*
* Hint: Starting with Reader.sequence will be important.
*/
def indirect(name: String): Reader[Config, List[String]] =
???
}