Monadic Zero
Do U remember second state of Response - Marvelous?
If we represent Marvelous via Answer with null inside - it's not enough, than we can translate Marvelous into Answer - ignoring it's Essentials - that is error:
val box = new Answer[Any](null)
val func:(Any)=>Int = (in) => 5
val res = box map func // Produces Answer(5)
Expected behavior, that is described via The First Zero Law: Identity
mzero map/flatMap f = mzero
Our Monadic zero wasn't enough zero to do this.
We don't try to make a difference between two Marvelous, declaration is enough, value is absent. From OOP point of view it's a Singleton, don't beget a lot of instances)
case object Marvelous extends Response[Nothing](false) {
def value = throw new NoSuchElementException("Something is wrong inside")
def map[B](func: Nothing => B) = Marvelous
}
This Zero should work:
val box = Marvelous
val res = box map {_.toString} // Returns Marvelous
Applying it twice and still getting the same
val box = Marvelous
val res = box map {_.toString} map {_ == Marvelous} // Returns Marvelous
This Zero should work:
val box = Marvelous
val res = box map {_.toString} // Returns Marvelous
Applying it twice and still getting the same
val box = Marvelous
val res = box map {_.toString} map {_ == Marvelous} // Returns Marvelous
Value is Nothing - try to get it returns Exception. Flag isStable set to true) Maping nothing to n
Monadic Zero comes with few Laws; The Second Zero Law: M to Zero
m flatMap {x=> mzero} ≡ mzero
Monadic Zero comes with few Laws; The Second Zero Law: M to Zero
m flatMap {x=> mzero} ≡ mzero
Plus Method
To introduce the last Monadic law, we need to refer to operation that can be done with Monads '+'.
"Add" operator for Monadic classes should mean the same as for other types:
"Add" operator for Monadic classes should mean the same as for other types:
Type | Method |
---|---|
Int | + |
List | ::: |
Option | orElse |
While Response Monad is almost Option clone, it makes cense to reuse "orElse" method name. It should return alternative value if Response is invalid:
final def orElse[B >: A](alternative: => Response[B]): Response[B] =
if (isStable) this else alternative
I prefer to put implementation into Answer and Marvelous classes:
final case class Answer[+A](value: A) extends Response[A](true) {
...
def orElse[B >: A](alternative: => Response[B]) = this
}
case object Marvelous extends Response[Nothing](false) {
...
def orElse[B >: Nothing](alternative: => Response[B]) = alternative
}
Here we have a orElse method that implements plus functionality, we are ready to introduce The
Third and Fourth Zero Laws: Plus
Filter
Monadic zero and plus operation are basis to new Monadic feature - Filter
Filtering is applying predicate (boolean-value function).
def filter(p: A=> Boolean): M[A] = ...
For example there is a list [-1, 1, 2] and predicate function x > 0. We need to get a list from original one that has only elements which make predicate return true [1, 2]. To get this result we can present filter via flatMap:
m flatMap {x => if(p(x)) unit(x) else mzero}
applying this returns mzero plus unit(1) plus unit (2), as U remember mzero plus something is something, then result is [1,2]
Let's implement filter function following OOP rules as well - declare in superclass and implement in children, but this is the time when one children Answer should know about another one Monadic zero:
sealed abstract class Response[+A](val isStable: Boolean) {
...
def filter(p: A => Boolean): Response[A]
}
final case class Answer[+A](value: A) extends Response[A](true) {
...
def filter(p: A => Boolean): Response[A] =
if (p(value)) this else Marvelous
}
case object Marvelous extends Response[Nothing](false) {
...
def filter(p: Nothing => Boolean): Response[Nothing] =
Marvelous
}
At the end few laws:
No comments:
Post a Comment