forked from markhibberd/introduction-to-fp-in-scala
-
Notifications
You must be signed in to change notification settings - Fork 5
/
Copy pathOptional.scala
113 lines (103 loc) · 2.46 KB
/
Optional.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
package intro
/*
* Optional is a data type used to represent a value which may
* or may not be set. An optional may either be _Full_ and contain
* a value _or_ be _Empty_ and not contain a value.
*
* This is directly equivalent to the Option type in the scala
* standard library where Some -> Full, and None -> Empty.
*/
sealed trait Optional[A] {
/*
* Implement fold for Optional.
*
* We often want to work with data structures be breaking them
* down by cases. All algebraic data structures can be broken
* down in the same way, a function is provided to handle each
* case, with the arguments to the data constructors matching the
* arguments to the fold functions.
*
* scala> Full(1).fold(x => x, 0)
* = 1
*
* scala> Empty().fold(x => x, 0)
* = 0
*/
def fold[X](
full: A => X,
empty: => X
): X =
???
/*
* Implement map for Optional[A].
*
* The following laws must hold:
* 1) r.map(z => z) == r
* 2) r.map(z => f(g(z))) == r.map(g).map(f)
*
* scala> Full(1).map(x => x + 10)
* = Full(11)
*
* scala> Empty[Int]().map(x => x + 10)
* = Emptyy()
*/
def map[B](f: A => B): Optional[B] =
???
/*
* Implement flatMap.
*
* The following law must hold:
* r.flatMap(f).flatMap(g) == r.flatMap(z => f(z).flatMap(g))
*
* scala> Full(1).flatMap(x => Full(x + 10))
* = Full(11)
*
* scala> Full(1).flatMap(x => Empty[Int]())
* = Empty(Unauthorized)
*
* scala> Empty[Int]().map(x => Full(x + 10))
* = Empty()
*
* Advanced: Try using fold.
*/
def flatMap[B](f: A => Optional[B]): Optional[B] =
???
/*
* Extract the value if it is success case otherwise use default value.
*
*
* scala> Full(1).getOrElse(10)
* = 1
*
* scala> Empty[Int]().getOrElse(10)
* = 10
*/
def getOrElse(otherwise: => A): A =
???
/*
* Implement choice, take this result if successful otherwise take
* the alternative.
*
* scala> Full(1) ||| Full(10)
* = Full(1)
*
* scala> Full(1) ||| Empty[Int]()
* = Full(1)
*
* scala> Empty[Int]() ||| Full(10)
* = Full(10)
*
* scala> Empty[Int]() ||| Empty[Int]()
* = Empty()
*/
def |||(alternative: => Optional[A]): Optional[A] =
???
}
case class Full[A](a: A) extends Optional[A]
case class Empty[A]() extends Optional[A]
object Optional {
def empty[A]: Optional[A] =
Empty()
def ok[A](value: A): Optional[A] =
Full(value)
}