Skip to content

Commit

Permalink
Merge pull request fpinscala#401 from aloshbennett/master
Browse files Browse the repository at this point in the history
Split lengthy comments into multiple lines.
  • Loading branch information
runarorama committed Mar 19, 2015
2 parents 4fae6ee + d9476b3 commit 264a0f5
Show file tree
Hide file tree
Showing 2 changed files with 22 additions and 10 deletions.
14 changes: 10 additions & 4 deletions answers/src/main/scala/fpinscala/errorhandling/Either.scala
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
package fpinscala.errorhandling


import scala.{Option => _, Either => _, _} // hide std library `Option` and `Either`, since we are writing our own in this chapter
//hide std library `Option` and `Either`, since we are writing our own in this chapter
import scala.{Option => _, Either => _, _}

sealed trait Either[+E,+A] {
def map[B](f: A => B): Either[E, B] =
Expand Down Expand Up @@ -54,14 +55,19 @@ object Either {
traverse(es)(x => x)

/*
There are a number of variations on `Option` and `Either`. If we want to accumulate multiple errors, a simple approach is a new data type that lets us keep a list of errors in the data constructor that represents failures:
There are a number of variations on `Option` and `Either`. If we want to accumulate multiple errors, a simple
approach is a new data type that lets us keep a list of errors in the data constructor that represents failures:
trait Partial[+A,+B]
case class Errors[+A](get: Seq[A]) extends Partial[A,Nothing]
case class Success[+B](get: B) extends Partial[Nothing,B]
There is a type very similar to this called `Validation` in the Scalaz library. You can implement `map`, `map2`, `sequence`, and so on for this type in such a way that errors are accumulated when possible (`flatMap` is unable to accumulate errors--can you see why?). This idea can even be generalized further--we don't need to accumulate failing values into a list; we can accumulate values using any user-supplied binary function.
There is a type very similar to this called `Validation` in the Scalaz library. You can implement `map`, `map2`,
`sequence`, and so on for this type in such a way that errors are accumulated when possible (`flatMap` is unable to
accumulate errors--can you see why?). This idea can even be generalized further--we don't need to accumulate failing
values into a list; we can accumulate values using any user-supplied binary function.
It's also possible to use `Either[List[E],_]` directly to accumulate errors, using different implementations of helper functions like `map2` and `sequence`.
It's also possible to use `Either[List[E],_]` directly to accumulate errors, using different implementations of
helper functions like `map2` and `sequence`.
*/
}
18 changes: 12 additions & 6 deletions answers/src/main/scala/fpinscala/errorhandling/Option.scala
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package fpinscala.errorhandling


import scala.{Option => _, Either => _, _} // hide std library `Option` and `Either`, since we are writing our own in this chapter
//hide std library `Option` and `Either`, since we are writing our own in this chapter
import scala.{Option => _, Either => _, _}

sealed trait Option[+A] {
def map[B](f: A => B): Option[B] = this match {
Expand Down Expand Up @@ -51,18 +51,22 @@ case object None extends Option[Nothing]

object Option {
def failingFn(i: Int): Int = {
val y: Int = throw new Exception("fail!") // `val y: Int = ...` declares `y` as having type `Int`, and sets it equal to the right hand side of the `=`.
// `val y: Int = ...` declares `y` as having type `Int`, and sets it equal to the right hand side of the `=`.
val y: Int = throw new Exception("fail!")
try {
val x = 42 + 5
x + y
}
catch { case e: Exception => 43 } // A `catch` block is just a pattern matching block like the ones we've seen. `case e: Exception` is a pattern that matches any `Exception`, and it binds this value to the identifier `e`. The match returns the value 43.
// A `catch` block is just a pattern matching block like the ones we've seen. `case e: Exception` is a pattern
// that matches any `Exception`, and it binds this value to the identifier `e`. The match returns the value 43.
catch { case e: Exception => 43 }
}

def failingFn2(i: Int): Int = {
try {
val x = 42 + 5
x + ((throw new Exception("fail!")): Int) // A thrown Exception can be given any type; here we're annotating it with the type `Int`
// A thrown Exception can be given any type; here we're annotating it with the type `Int`
x + ((throw new Exception("fail!")): Int)
}
catch { case e: Exception => 43 }
}
Expand All @@ -88,7 +92,9 @@ object Option {
case h :: t => h flatMap (hh => sequence(t) map (hh :: _))
}
/*
It can also be implemented using `foldRight` and `map2`. The type annotation on `foldRight` is needed here; otherwise Scala wrongly infers the result type of the fold as `Some[Nil.type]` and reports a type error (try it!). This is an unfortunate consequence of Scala using subtyping to encode algebraic data types.
It can also be implemented using `foldRight` and `map2`. The type annotation on `foldRight` is needed here; otherwise
Scala wrongly infers the result type of the fold as `Some[Nil.type]` and reports a type error (try it!). This is an
unfortunate consequence of Scala using subtyping to encode algebraic data types.
*/
def sequence_1[A](a: List[Option[A]]): Option[List[A]] =
a.foldRight[Option[List[A]]](Some(Nil))((x,y) => map2(x,y)(_ :: _))
Expand Down

0 comments on commit 264a0f5

Please sign in to comment.