In Scala, I am thinking of a simple monad Result
that contains either a Good
value, or alternatively an Error
message. Here is my implementation.
I'd like to ask: Did I do something in an excessively complicated manner? Or mistakes even?
Could this be simplified (but maintaining readability, so no Perl golf)? For example, do I need to use the abstract class and the companion object, or could it be simpler to put everything in a normal class?
abstract class Result[+T] {
def flatMap[U](f: T => Result[U]): Result[U] = this match {
case Good(x) => f(x)
case e: Error => e
}
def map[U](f: T => U): Result[U] = flatMap { (x: T) => Result(f(x)) }
}
case class Good[T](x: T) extends Result[T]
case class Error(e: String) extends Result[Nothing]
object Result { def apply[T](x: T): Result[T] = Good(x) }
Now if I, for example
val x = Good(5)
def f1(v: Int): Result[Int] = Good(v + 1)
def fE(v: Int): Result[Int] = Error("foo")
then I can chain in the usual manner:
x flatMap f1 flatMap f1 // => Good(7)
x flatMap fE flatMap f1 // => Error(foo)
And the for-comprehension:
for (
a <- x;
b <- f1(a);
c <- f1(b)
) yield c // => Good(7)
P.S: I am aware of the \/
monad in Scalaz, but this is for simple cases when installing and importing Scalaz feels a bit heavy.