% CSci 555: Functional Programming \
  Functional Programming in Scala \
  Handling Errors without Exceptions
% **H. Conrad Cunningham**
% **7 March 2019**

---
lang: en
---

| Copyright (C) 2016, 2018, 2019,
  [H. Conrad Cunningham ](<http://www.cs.olemiss.edu/~hcc>)
| Professor of 
  [Computer and Information Science ](<https://www.cs.olemiss.edu>)
| [University of Mississippi ](<http://www.olemiss.edu>)
| 211 Weir Hall
| P.O. Box 1848
| University, MS 38677
| (662) 915-5358


**Note:** This set of notes accompanies my lectures on Chapter 4 of
the book *Functional Programming in Scala* \[Chiusano 2015\] 
(i.e. the Red Book).

**Prerequisites**: In this set of notes, I assume the reader is
familiar with the programming concepts and Scala features covered in
my *Notes on Scala for Java Programmers* \[Cunningham 2019a\],
*Recursion Styles, Correctness, and Efficiency (Scala Version)*
\[Cunningham 2019b\], *Type System Concepts* \[Cunningham 2019c\],
and *Functional Data Structures* \[Cunningham 2019d\] (i.e. Chapter 3
of the Red Book \[Chuisano 2015\]).

**Browser Advisory:** The HTML version of this textbook requires a
browser that supports the display of MathML. A good choice as of
March 2019 is a recent version of Firefox from Mozilla.


\newpage
\setcounter{section}{3}

# Handling Errors without Exceptions

## Introduction

A benefit of Java or Scala exception handling (i.e. using
`try`{.scala}-`catch`{.scala} blocks) is that it consolidates error
handling to well-defined places in the code.

However, code that throws exceptions typically exhibits two problems
for functional programming.

1.  It is not *referentially transparent*. It has side effects. Its
    meaning is thus dependent upon the context in which it is
    executed.

2.  It is not *type safe*. Exceptions may cause effects that are of a
    different type than the return value of the function.

*The key idea* from Chapter 4 *is to use ordinary data values to
represent failures and exceptions* in programs.  This preserves
referential transparency and type safety while also preserving the
benefit of exception-handling mechanisms, that is, the consolidation
of error-handling logic.

To do this, we introduce the `Option`{.scala} and `Either`{.scala}
algebraic data types. These are standard types in the Scala library,
but for pedagogical purposes Chapter 4 introduces its own definition
that is similar to the standard one.

This set of notes also introduces Scala features that we have not
previously discussed extensively: type variance, call-by-name
parameter passing, and for-comprehensions.

## Aside: On Null References

What should a function do when it is required to return an object but
no suitable object exists?

One common approach is to return a *null reference*.  British
computing scientist Tony Hoare, who introduced the null reference into
the Algol type system in the mid-1960s, calls that his "billion dollar
mistake" because it "has led to innumerable errors, vulnerabilities,
and system crashes" \[Hoare 2009\].

The software patterns community documented a safer approach to this
situation by identifying the *Null Object* design pattern
\[Woolf 1998\]\[Wikipedia 2019\].  This well-known object-oriented
pattern seeks to "encapsulate the absence of an object by providing a
substitutable alternative that offers suitable default do nothing
behavior" \[SourceMaking 2019\]. That is, the object must be of the
correct type. It must be possible to apply all operations on that type
to the object. But the operations should have a neutral behavior, with
no side effects. The null object should actively do nothing!

The functional programming community introduced *option types*
(e.g. Haskell's `Maybe`{.haskell} and `Either`{.haskell} types) as an
approach to the same general problem. Scala's `Option`{.scala} and
`Either`{.scala} correspond to Haskell's `Maybe`{.haskell} and
`Either`{.haskell} types. Rust's `Option`{.rust} and Swift's
`Optional`{.swift} are similar to Haskell's `Maybe`{.haskell}.

The concept of *nullable types* \[Wikipedia 2019\], such as Java's
`Optional`{.java}, Python's `None`{.python}, and C\#'s `?`{.cs} type
annotations, are closely related to option types.


## An `Option` Algebraic Data Type 

We define a Scala algebraic data type `Option`{.scala} using sealed
trait `Option`{.scala} with case class `Some`{.scala} to wrap a value
and case object `None`{.scala} to denote an empty value. We specify
the operations on the data type using the *method-chaining* style.

~~~{.scala}
    import scala.{Option => _, Either => _, _} // hide standard
    sealed trait Option[+A] {
        def map[B](f: A => B): Option[B] 
        def getOrElse[B >: A](default: => B): B 
        def flatMap[B](f: A => Option[B]): Option[B]
        def orElse[B >: A](ob: => Option[B]): Option[B]
        def filter(f: A => Boolean): Option[A]
    }
    case class Some[+A](get: A) extends Option[A]
    case object None extends Option[Nothing]
~~~

The `import`{.scala} statement above hides the standard definitions of
`Option`{.scala} and `Either`{.scala} from the Scala standard
library. The versions developed in this chapter are similar, but add
useful features above what is available in the standard library.

Before we move on to the definition of these methods, let's review the
concept of method chaining and then consider issues raised in the
signatures of the `getOrElse`{.scala} and `orElse`{.scala} methods:
one related to the generic parameters and the other to the
`default`{.scala} parameters.


### Method chaining in Scala

Consider function `map`{.scala} in the `Option`{.scala} trait. It is
implemented in this chapter as a method on the classes that extend the
`Option`{.scala} trait. 

Method `map`{.scala} takes two arguments and returns a result
object. Its implicit "left" argument is the receiver object for the
method call, an `Option`{.scala} object represented internally by the
variable `this`{.scala}. Its explicit "right" argument is a
function. The result returned is itself an `Option`{.scala} object.

Suppose `obj`{.scala} is an `Option[A]`{.scala} object and `f`{.scala}
is an `A => B`{.scala} function. In standard object-oriented style, we
can issue the call `obj.map(f)`{.scala} to operate on object
`obj`{.scala} with method `map`{.scala} and argument
`f`{.scala}. Scala allows us to apply such a method in an *infix
operator* style as follows:

~~~{.scala}
    obj map f
~~~

Note that `map`{.scala} takes an `Option[A]`{.scala} as its left
operand (i.e. argument) and returns an `Option[B]`{.scala} object as
its result. Thus we can *chain* such method calls as follows (where
functions `p`{.scala} and `g`{.scala} have the appropriate types):

~~~{.scala}
    obj.map(f).filter(p).map(g)
~~~

In Scala's infix operator style, this would be:

~~~{.scala}
    (obj map f) filter p)) map g
~~~

But these operators associate to the left, so can leave off the
parentheses and write the above as follows

~~~{.scala}
    obj map f filter p map g
~~~
 
or perhaps more readably as:

~~~{.scala}
    obj map(f) filter(p) map(g)
~~~

Note that this last way of writing the chain suggests the *data flow*
nature of this computation. The data originates with the source
`obj`{.scala}, which is then transformed by a `map(f)`{.scala}
operator, then by a `filter(p)`{.scala} operator, and then by a
`map(g)`{.scala} operator to give the final result.
 
Now let's consider an issue raised in the signatures of the
`getOrElse`{.scala} and `orElse`{.scala} methods related to the
generic parameter.


### Type variance issues

As we have discussed previously, the `+A`{.scala} annotation in the
`Option[+A]`{.scala} definition declares that parameter `A`{.scala} is
*covariant*.  That is, if `S`{.scala} is a subtype of `T`{.scala},
then `Option[S]`{.scala} is a subtype of `Option[T]`{.scala}.  Also
remember that `Nothing`{.scala} is a subtype of all other types.

For example, suppose type `Beagle`{.scala} is a subtype of type
`Dog`{.scala}, which, in turn, is a subtype of type
`Mammal`{.scala}. Then, because of the covariant definition,
`Option[Beagle]`{.scala} is a subtype of `Option[Dog]`{.scala}, which
is a subtype of `Option[Mammal]`{.scala}. This is intuitively what we
expect.

However, in `getOrElse`{.scala} and `orElse`{.scala}, we use type
constraint `B >: A`{.scala}. This means that `B`{.scala} must be equal
to `A`{.scala} or a supertype of `A`{.scala}. We also define value
parameter of these functions to have type `Option[B]`{.scala} instead
of `Option[A]`{.scala}.

Why must we have this constraint?

See the [chapter notes
](<https://github.com/fpinscala/fpinscala/wiki>) for the *Functional
Programming in Scala* book \[Chiusano 2015\] for more detail on this
complicated issue. We sketch the argument below.

In some sense, the `+A`{.scala} annotation declares that, in all
contexts, it is safe to cast this type `A`{.scala} to some supertype
of `A`{.scala}. The Scala compiler does not allow us to use this
annotation unless we can cast all members of a type safely.

Suppose we declare `orElse`{.scala} (incorrectly!) as follows:

~~~{.scala}
    trait Option[+A] {
        def orElse(o: Option[A]): Option[A]
		... 
    }
~~~

We have a problem because this declaration of `orElse`{.scala} only
allows us to cast `A`{.scala} to a subtype of `A`{.scala}.

Why?

As with any function, `orElse`{.scala} can only be safely passed a
subtype of its declared input type. That is, a function of type
`Dog => R`{.scala} can be passed an object of subtype like
`Beagle`{.scala} or of type `Dog`{.scala} itself, but it cannot be
passed a supertype object of `Dog`{.scala} such as `Mammal`{.scala}. 

As we saw in the notes on Chapter 3 \[Cunningham 2019d\], Scala
functions are contravariant in their input types.

But `orElse`{.scala} has a parameter type of `Option[A]`{.scala}.
Because of the covariance of `A`{.scala} (declared in the trait), this
parameter only allows subtypes of `A`{.scala}---not supertypes as
required by the covariance.

So, we have a contradiction. 

For the incorrect signature of `orElse`{.scala}, the Scala compiler
generates an error message such as "Covariant type `A`{.scala} occurs
in contravariant position." 

We can get around this error by using a more complicated signature
that does not mention `A`{.scala} (declared in the trait) in any of
the function arguments, such as:

~~~{.scala}
    trait Option[+A] {
        def orElse[B >: A](o: Option[B]): Option[B]
		... 
    }
~~~

Now consider the second new feature appearing in the signatures of
`getOrElse`{.scala} and `orElse`{.scala}---the `=> B`{.scala} and
`=> Option[B]`{.scala} types for the parameters.


### Parameter-passing modes

Scala's primary parameter-passing mode is *call by value* as in Java
and C. That is, the program evaluates the caller's argument and the
resulting value is bound to the corresponding formal parameter within
the called function.

If the argument's value is of a primitive type, then the value itself
is passed.  If the value is an object, then the address of (i.e.
reference to) the object is passed.
 
A call-by-value parameter is called *strict* because the called
function always requires that parameter's value before it can
execute. The corresponding argument must be evaluated *eagerly* before
transferring control to the called function.
 
Scala also has *call-by-name* parameter passing.  Consider the
`default: => B`{.scala} feature in the declaration

~~~{.scala}
    def getOrElse[B >: A](default: => B): B
~~~

The type notation `=> B`{.scala} means the calling program leaves the
argument of type `B`{.scala} unevaluated. That is, the calling program
wraps the argument expression in an parameterless function and passes
the function to the called method.  This automatically generated
parameterless function is sometimes called a *thunk*.

Every reference to the corresponding parameter causes the thunk to be
evaluated. If the method does not access the corresponding parameter
during some execution, then the parameter is never evaluated.

As with all higher-order arguments in Scala, a thunk is passed as a
*closure*. In addition to the function, the closure captures any *free
variables* occurring in the expression---that is, the variables defined
in the caller's environment but not within the expression itself.

Note: The closure actually captures the variable itself, not its
value. So if the free variable is either a reference to a
`var`{.scala} or to a mutable data structure, then changes in the
value are seen inside the called function. But in this course, we
normally use immutable data structures and `val`{.scala} declarations.

A call-by-name parameter is called *nonstrict* because the called
function does not always require that parameter's value for its
execution. The corresponding argument can thus be evaluated *lazily*,
that is, evaluated only if and when its value is needed.

We look at more implications of strict and nonstrict functions in
Chapter 5 \[Chiusano 2015\].

Note: See 
[`ClosureExample.scala` ](<../Closures/ClosureExample.scala>)
and
[`ThunkExample.scala` ](<../Closures/ThunkExample.scala>)
for examples of using closures and thunks, respectively.


### Implementing the `Option` methods

Now, let's define the methods in the `Option`{.scala} data type.

Above we defined the trait `Option`{.scala} as follows. It is
parameterized by covariant type `A`{.scala}.

~~~{.scala}
    import scala.{Option => _, Either => _, _} // hide standard
    sealed trait Option[+A] {
        def map[B](f: A => B): Option[B] 
        def getOrElse[B >: A](default: => B): B
        def flatMap[B](f: A => Option[B]): Option[B]
        def orElse[B >: A](ob: => Option[B]): Option[B]
        def filter(f: A => Boolean): Option[A]
    }
    case class Some[+A](get: A) extends Option[A]
    case object None extends Option[Nothing]
~~~

The `Option`{.scala} data type is similar to a list that is either
empty or has one element. As with the `List`{.scala} algebraic data
type from Chapter 3, we *follow the types to implementations*. (This
is sometimes called *type-driven development*.) That is, we use the
form of the data to guide us to design the form of the function.

The `map`{.scala} method applies a function to its implicit
`Option[A]`{.scala} argument. If the implicit argument is a
`Some`{.scala}, the method applies the function to the wrapped value
and returns the resulting `Some`{.scala}. If it is a `None`{.scala},
the method just returns `None`{.scala}. We can implement `map`{.scala}
using pattern matching directly as follows:

~~~{.scala}
    def map[B](f: A => B): Option[B] = this match {
        case None    => None
        case Some(a) => Some(f(a))
    }
~~~

Similarly, we can use pattern matching directly to implement the
`getOrElse`{.scala} function. If the implicit argument is of type
`Some`{.scala}, this function returns the value it wraps. If the
implicit argument is of type `None`{.scala}, this function returns the
value denoted by the `default`{.scala} argument. By passing
`default`{.scala} by name, the argument is only evaluated when its
value is needed.

~~~{.scala}
    def getOrElse[B >: A](default: => B): B = this match {
        case None    => default // evaluate the thunk
        case Some(a) => a
    }
~~~

Function `flatMap`{.scala} applies its argument function `f`{.scala},
which might fail, to its implicit `Option`{.scala} argument when this
value is not `None`{.scala}.  We can define `flatMap`{.scala} in terms
of `map`{.scala} and `getOrElse`{.scala} as shown below. (Reminder: If
we apply method names as operators in an infix manner, they associate
to the left. The leftmost operator implicitly operates on
`this`{.scala} object.)

~~~{.scala}
    def flatMap[B](f: A => Option[B]): Option[B] =
        map(f) getOrElse None
~~~

We can also define `flatMap`{.scala} using pattern matching directly.

~~~{.scala}
    def flatMap_1[B](f: A => Option[B]): Option[B] = this match {
       case None    => None
       case Some(a) => f(a)
    }
~~~

Function `orElse`{.scala} returns the implicit `Option`{.scala}
argument if is not `None`{.scala}; otherwise, it returns the explicit
`Option`{.scala} argument.  We can define `orElse`{.scala} in terms of
`map`{.scala} and `getOrElse`{.scala} or by directly using pattern
matching.

~~~{.scala}
    def orElse[B >: A](ob: => Option[B]): Option[B] =
        this map (Some(_)) getOrElse ob

    def orElse_1[B>:A](ob: => Option[B]): Option[B] = 
	    this match {
            case None => ob
            case _    => this
        }
~~~

The `filter`{.scala} function converts its implicit argument from
`Some`{.scala} to `None`{.scala} if it does not satisfy the boolean
function `p`{.scala}. We can define `filter`{.scala} by using pattern
matching directly or by using `flatMap`{.scala}.

~~~{.scala}
    def filter(p: A => Boolean): Option[A] = 
	    this match {
            case Some(a) if p(a) => this
            case _               => None
        }

    def filter_1(p: A => Boolean): Option[A] =
        flatMap(a => if (p(a)) Some(a) else None)
~~~


### Using `Option` for statistical `mean` and `variance`

Consider a function to calculate and return the *mean* (i.e. average
value) of a list of numbers. This function must sum the list of
numbers and divide by the number of elements. It might have a
signature such as:

~~~{.scala}
    def mean(xs: List[Double]): Double
~~~

But what should be returned for empty lists?

We can modify the signature to use `Option`{.scala} and define the
function as follows:

~~~{.scala}
    def mean(xs: Seq[Double]): Option[Double] =
        if (xs.isEmpty) 
		    None
        else 
		    Some(xs.sum / xs.length)
~~~

The return type now allows the possibility that the mean may be
undefined. We thus extend a partial function to a total function in a
meaningful way.
 
Above we also generalize the `List`{.scala} type to its supertype
`Seq`{.scala} from the Scala library.  Type `Seq`{.scala} denotes a
family of sequential data types that includes the `List`{.scala} type,
array-like collections, etc. This type defines the methods
`isEmpty`{.scala}, `sum`{.scala}, and `length`{.scala}.
 
If the mean of a sequence $s$ is $m$, then the (statistical)
*variance* of the sequence $s$ is the mean of the sequence formed by
the terms $(x-m)^{2}$ for each $x \in s$ (perserving the order).

Using the `mean`{.scala} function defined above, we can compute the
variance of a sequence of numbers as follows:

~~~{.scala}
    def variance(xs: Seq[Double]): Option[Double] =
        mean(xs) flatMap 
		    (m => mean(xs.map(x => math.pow(x - m, 2))))
~~~


### Using `Option` in the labelled digraph

In the doubly labelled `Digraph`{.scala} case study, we define the
following method to return the label on a vertex:

~~~{.scala}
    def getVertexLabel(ov: A): B
~~~

In the case study's `DigraphList`{.scala} implementation, we define this
function as follows. The function terminates with an error when the
the argument vertex is not present in the digraph.

~~~{.scala}
    def getVertexLabel(ov: A): B = 
        (vs dropWhile (w => w._1 != ov)) match {
            case Nil => 
			    sys.error("Vertex " + ov + " not in digraph")
            case ((_,l)::_) => l
        } 
~~~

We can avoid the error termination in this function by changing the
method signature to return an `Option[B]`{.scala} instead of a
`B`{.scala}.

~~~{.scala}
    def getVertexLabelOption(ov: A): Option[B] = 
        (vs dropWhile (w => w._1 != ov)) match {
            case Nil        => None
            case ((_,l)::_) => Some(l)
    } 
~~~

Code that uses this new `Digraph`{.scala} method can call the various
`Option`{.scala} methods (or directly use pattern matching) to process
the result appropriately.

For example, if the vertex label is a string, it may be appropriate in
some scenarios to just use a null string for the label of a
nonexistent vertex. Let `g`{.scala} be a `Digraph`{.scala} and be
`v`{.scala} be a possible vertex, then

~~~{.scala}
    (g getVertexLabelOption v) getOrElse ""
~~~

would either return the label string for `v`{.scala} if it exists or
the null string if `v`{.scala} does not exist.

Similarly, the code

~~~{.scala}
    (g getVertexLabelOption v) getOrElse 
	    (sys.error("undefined vertex " + v))
~~~

would still terminate with an error. However, this design enables the
user of the `Digraph`{.scala} library to decide under what
circumstances and at what point in the code to terminate.

Idiom: A common pattern for computing with the `Option`{.scala} type
is to use `map`{.scala}, `flatMap`{.scala}, and `filter`{.scala} to
transform values generated by a function like
`getVertexLabelOption`{.scala} and then to use `getOrElse`{.scala} for
error handling at the end.


### Lifting

It seems that that deciding to use of `Option`{.scala} could cause
lots of changes to ripple through our code, much like the introduction
of extensive exception-handling would. However, we can avoid that
somewhat by using a technique called *lifting*.

For example, the `Option`{.scala} type's `map`{.scala} function
enables us to transform values of type `Option[A]`{.scala} into values
of type `Option[B]`{.scala} using a function of type `A => B`{.scala}.

Alternatively, we could consider `map`{.scala} as transforming a
function of type `A => B`{.scala} into a function of type
`Option[A] => Option[B]`{.scala}.  That is, we *lift* an ordinary
function into a function on `Option`{.scala}.

We can formalize this alternative view with the following function:

~~~{.scala}
    def lift[A,B](f: A => B): Option[A] => Option[B] = _.map(f)
~~~

Thus any existing function can be transformed to work within the
context of a single `Option`{.scala} value. For example, we can lift the
square root function from type `Double`{.scala} to work with
`Option[Double]`{.scala} as follows:

~~~{.scala}
    def sqrtO: Option[Double] => Option[Double] = 
	    lift(math.sqrt _)
~~~

We can now use `sqrtO`{.scala} such as `sqrtO(Some(4))`{.scala}. This
evaluates to `Some(2)`{.scala}.

Chapter 4 of *Functional Programming in Scala* \[Chiusano 2015\] gives
several examples where `Option`{.scala} types can be used effectively
in realistic scenarios. One of these examples illustrates how to wrap
an exception-oriented API to provide users with `Option`{.scala}
results in error situations.

TODO: Add example of wrapping an exception-oriented API.

Note: See [`WrapException.scala` ](<WrapException.scala>) for examples
of how to wrap exception-throwing functions to return `Option`{.scala}
and `Either`{.scala} objects, respectively.


### For comprehensions

Another useful function on `Option`{.scala} data types is the function
`map2`{.scala} that combines two `Option`{.scala} values by lifting a
binary function.  If either of the arguments are `None`{.scala}, then
the result should also be `None`{.scala}.  We can define
`map2`{.scala} as follows:

~~~{.scala}
    def map2[A,B,C](a: Option[A], b: Option[B])(f: (A, B) => C): 
	    Option[C] =
            a flatMap (aa => 
		        b map (bb => 
		            f(aa, bb)))
~~~

This function applies a series of `map`{.scala} and `flatMap`{.scala} calls.

Because lifting is so common in functional programming, Scala provides
a syntactic construct called a *for-comprehension* to facilitate its
use. This construct is really *syntactic sugar* for a series of
applications of `map`{.scala}, `flatMap`{.scala}, and
`withFilter`{.scala}. (Method `withFilter`{.scala} works like
`filter`{.scala} except it filters on demand, without creating a new
collection as a result.)

Here is the same code expressed as a for-comprehension:

~~~{.scala}
    def map2fc[A,B,C](a: Option[A], b: Option[B])(f: (A, B) => C): 
	    Option[C] =
            for { 
			    aa <- a
			    bb <- b 
            } yield f(aa, bb)
~~~

Of course, for-comprehensions are more general than just their use
with `Option`{.scala}. They can be used for the lists, arrays,
iterators, ranges, streams, and other types in the Scala standard
library that support the `map`{.scala}, `flatMap`{.scala}, and
`withFilter`{.scala} (or `filter`{.scala}) operations. 

Consider a list `persons`{.scala} of person objects with
`name`{.scala} and `age`{.scala} fields.  We can collect the names of
all persons who are age 21 and above as follows:

~~~{.scala}
    for (p <- persons if p.age >= 21) yield p.name
~~~

This is equivalent to the following `List`{.scala} expression

~~~{.scala}
    filter (p => p.age >= 21) map (p => p.name)
~~~


### Translating (desugaring) for-comprehensions

In general, a for-comprehension

~~~{.scala}
    for (enums) yield e
~~~

evaluates expression `e`{.scala} for each binding generated by the
enumerator sequence `enums`{.scala} and collects the results. An
enumerator sequence begins with a generator and may be followed by
additional generators, value definitions, and guards.

-    A *generator* `p <- e`{.scala} produces a sequence of zero or
     more bindings from expression `e`{.scala} by matching each value
     against pattern `p`{.scala}.

-   A *value definition* `p = e`{.scala} binds the names in pattern
    `p`{.scala} to the result of evaluating the expression
    `e`{.scala}.

-   A *guard* `if e`{.scala} restricts the bindings to those that satisfy the
    boolean expression `e`.


We can translate (or *desugar*) for-comprehension (more or less) as
follows:

1.  We replace every generator `p <- e`{.scala}, where `p`{.scala} is
    a pattern and `e`{.scala} is an expression, by:

    ~~~{.scala}
        p <- e.withFilter { case p => true ; case _ => false }
    ~~~

    Here we use `withFilter`{.scala} to filter out those items that do not
    match the pattern `p`{.scala}.


2.  While all comprehension have not been eliminated, repeat the
    following:

    a.  Translate for-comprehension 
	
        ~~~{.scala}
	        for (p <- e) yield e1
        ~~~
		
		to the expression:
		
        ~~~{.scala}
		    e.map { case p => e1 }
        ~~~

    b.  Translate for-comprehension 

        ~~~{.scala}
	        for (p <- e; p1 <- e1; ... ) yield e2 
        ~~~

		where `...`{.scala} is a (possibly empty) sequence of generators,
        definitions, or guards, to the expression:
		
        ~~~{.scala}
		    e.flatMap { case p => for (p1 <- e1; ... ) yield e2 }
        ~~~

    c.  Translate a generator `p <- e`{.scala} followed by a guard 
	    `if g`{.scala} to a single generator
		
        ~~~{.scala}
		    p <- e.withFilter((x1,...,xn) => g)
        ~~~
			
		where `x,...,xn`{.scala} are the free variables of `p`{.scala}.


    d.  Translate a generator `p <- e`{.scala} followed by a value
        definition `p1 = e1`{.scala} to the following generator of
        pairs of values, where `x`{.scala} and `x1`{.scala} are fresh
        names:

        ~~~{.scala}
            (p, p1) <- for (x@p <- e) yield
                { val x1@p1 = e1; (x, x1) }
        ~~~

The Scala notation `x@p`{.scala} means that name `x`{.scala} is bound
to the value of the expression `p`{.scala}.

Note: Above we do not consider the imperative for-loops. These can
also be translated as above except that the imperative method
`forEach`{.scala} is also needed.

As an example, we can translate (desugar) the for-comprehension

~~~{.scala}
    for(x <- e1; y <- e2; z <- e3) yield {...}
~~~

into the expression:

~~~{.scala}
    e1.flatMap(x => e2.flatMap(y => e3.map(z => {...}))) 
~~~
	  
As a second example, we can also translate the for-comprehension

~~~{.scala}
    for(x <- e; if p) yield {...}
~~~

into the expression:

~~~{.scala}
    e.withFilter(x => p).map(x => {...})
~~~
	   
If no `withFilter`{.scala} method is available, we can instead use:

~~~{.scala}
    e.filter(x => p).map(x => {...}) 
~~~

As a third example, we can translate for-comprehension

~~~{.scala}
    for(x <- e1; y = e2) yield {...}
~~~

into the expression:

~~~{.scala}
    e1.map(x => (x, e2)).map((x,y) => {...}) 
~~~


### Adding for-comprehensions to data types

The Scala language has no typing rules for the for-comprehensions
themselves. The Scala compiler first translates for-comprehensions
into calls on the various method and then checks the types. It does
not require that methods `map`{.scala}, `flatMap`{.scala}, and
`withFilter`{.scala} have particular type signatures.  However, a
particular setup for some collection type `C`{.scala} with elements of
type `A`{.scala} is the following:

~~~{.scala}
    trait C[A] {
        def map[B](f: A => B): C[B]
        def flatMap[B](f: A => C[B]): C[B]
        def withFilter(p: A => Boolean): C[A]
    }
~~~

We can define our own data types to support for-comprehension by
providing one or more of the required operations above.

-   If the data type defines just `map`{.scala}, Scala allows
    for-comprehensions consisting of a single generator.

-   If the data type defines both `flatMap`{.scala} and `map`{.scala},
    Scala allows for-comprehensions consisting of several generators.
	
-   If the data type defines `withFilter`{.scala}, Scala allows
    for-comprehensions with guards.  (If `withFilter`{.scala} is not defined
    but `filter`{.scala} is, Scala will currently use `filter`{.scala}
    instead. However, this gives a deprecation warning, so this
    fallback feature may be eliminated in a future release of Scala.)


We added for-comprehensions to our own `Option`{.scala} type
earlier. We do the same for the `Either`{.scala} type in the next
section.

Note: A for-comprehension is, in general, convenient syntactic sugar
for expressing compositions of monadic operators. If time allows, we
will discuss monads later in the semester.


## An `Either` Algebraic Data Type 

We can use data type `Option`{.scala} to encode that a failure or exception
has occurred.  However, it does not give any information about what
went wrong.

We can encode this additional information using the algebraic data
type `Either`{.scala}.

~~~{.scala}
    import scala.{Option => _, Either => _, _} // hide builtin
    sealed trait Either[+E,+A] {
        def map[B](f: A => B): Either[E,B]
        def flatMap[EE >: E, B](f: A => Either[EE,B]): 
		    Either[EE,B]
        def orElse[EE >: E, AA >: A](b: => Either[EE,AA]): 
		    Either[EE,AA]
		def map2[EE >: E, B, C](b: Either[EE, B])(f: (A,B) => C): 
		    Either[EE, C] 
    }
    case class Left[+E](get: E) extends Either[E,Nothing]
    case class Right[+A](get: A) extends Either[Nothing,A]
~~~

By convention, we use the constructor `Right`{.scala} to denote
success and constructor `Left`{.scala} to denote failure.

We can implement `map`{.scala}, `flatMap`{.scala}, and
`orElse`{.scala} directly using pattern matching on the `Either` type.

~~~{.scala}
    def map[B](f: A => B): Either[E, B] = 
        this match {
            case Left(e)  => Left(e)
            case Right(a) => Right(f(a))
        }
   
    def flatMap[EE >: E, B](f: A => Either[EE, B]): 
	    Either[EE, B] = this match {
            case Left(e)  => Left(e)
            case Right(a) => f(a)
		}
			
    def orElse[EE >: E, AA >: A](b: => Either[EE, AA]): 
	    Either[EE, AA] = this match {
            case Left(_)  => b
            case Right(a) => Right(a)
		}
~~~

The availability of `flatMap`{.scala} and `map`{.scala} enable us to
use for-comprehension generators with `Either`{.scala}. We can thus
implement `map2`{.scala} using a for-comprehension, as follows:

~~~{.scala}
    def map2[EE >: E, B, C](b: Either[EE, B])(f: (A, B) => C): 
	    Either[EE, C] =
	        for { a <- this; b1 <- b } yield f(a,b1)
~~~

Let's again use `mean`{.scala} as an example and use a `String`{.scala} to describe
the failure in `Left`{.scala}.

~~~{.scala}
    def mean(xs: IndexedSeq[Double]): Either[String, Double] = 
        if (xs.isEmpty) 
            Left("mean of empty list!")
        else 
            Right(xs.sum / xs.length)
~~~

We can use the `Left`{.scala} value to encode more information, such
as the location of the error in the program.  For example, we might
catch and return the value of an `Exception`{.scala} generated as we
do in the `safeDiv`{.scala} function below.

~~~{.scala}
    def safeDiv(x: Int, y: Int): Either[Exception, Int] = 
        try Right(x / y)
            catch { case e: Exception => Left(e) }
~~~

We can abstract the computational pattern in the `safeDiv`{.scala}
function as function `Try`{.scala} defined below:

~~~{.scala}
    def Try[A](a: => A): Either[Exception, A] =
        try Right(a)  // evaluate thunk
        catch { case e: Exception => Left(e) }
~~~

Chapter 4 of *Functional Programming in Scala* \[Chiusano 2015\]
describes other functions for type `Either`{.scala}.


## Standard Library

Both `Option`{.scala} and `Either`{.scala} appear in the standard
library.

The standard library `Option`{.scala} type is similar to the one developed
here, but the library version is missing some of the extended
functions described in Chapter 4 \[Chiusano 2015\].

The standard library `Either`{.scala} type is similar but more complicated,
using projections on the left and right. It is also missing some of
the extended functions from Chapter 4 \[Chiusano 2015\].

Study the Scala API documentation for more information on these data
types.


## Summary

The big idea in this chapter is to use ordinary values to represent
exceptions and use higher-order functions for handling and propagating
errors. As examples, we considered the algebraic data types
`Option`{.scala} and `Either`{.scala} and functions such as
`map`{.scala}, `flatMap`{.scala}, `filter`{.scala}, and
`orElse`{.scala} to process their values.

We will use this general technique of using values to represent
effects in the subsequent studies in this course.

We introduced the idea of nonstrict functions.  We examine the
implications and use of these more in Chapter 5.


## Source Code for Chapter

-   [`Option2.scala` ](<Option2.scala>)

-   [`Either2.scala` ](<Either2.scala>)


## Exercises

TODO: Add


## Acknowledgements 

In Spring 2016, I wrote this set of notes to accompany my lectures on
Chapter 4 of the book *Functional Programming in Scala* \[Chiusano
2015\] (i.e. the Red Book). I constructed the notes around the ideas,
general structure, and Scala examples from that chapter and its
associated materials.

I also patterned some of the discussion of for-comprehensions on
Chapter 10 of the document *Scala by Example* by Martin Odersky
\[Odersky 2014\], on Chapter 23 of 2nd Edition of the book
*Programming in Scala* \[Odersky 2016\], on the relevant parts of the
Scala language specification, and on a relevant FAQ in the Scala
documentation.

In 2018 and 2019, I updated the format of the document to be more
compatible with my evolving document structures and corrected a few
errors. In 2019, I also added the sections on null references and
method chaining.

I maintain these notes as text in Pandoc's dialect of Markdown 
using embedded LaTeX markup for the mathematical formulas and then 
translate the notes to HTML, PDF, and other forms as needed. 


## References

\[Chiusano 2015\]: 
:   Paul Chiusano and Runar Bjarnason.  *Functional Programming in 
    Scala*, Manning, 2015.  This book is sometimes called the Red 
    Book.  The chapter notes for this book are available on GitHub 
    at <https://github.com/fpinscala/fpinscala/wiki>. 
	
\[Cunningham 2019a\]: 
: H. Conrad Cunningham.
    [*Notes on Scala for Java Programmers* 
	](<../ScalaForJava/ScalaForJava.html>),
    2019.

\[Cunningham 2019b\]: 
:   H. Conrad Cunningham. 
    [*Recursion Styles, Correctness, and Efficiency (Scala Version)*
	](<../RecursionStyles/RecursionStylesScala.html>), 2019. 

\[Cunningham 2019c\]: 
:   H. Conrad Cunningham. 
    [*Type System Concepts*
	](<../TypeConcepts/TypeSystemConcepts.html>), 2019. 

\[Cunningham 2019d\]: 
:   H. Conrad Cunningham. 
    [*Functional Data Structures*
	](<../FPS03/FunctionalDS.html>), 2019. 

\[Hoare 2009\]: 
: Tony Hoare.  Null References: The Billion Dollar Mistake,
    *InfoQ.com*, August 25, 2009,
    Available at 
	<https://www.infoq.com/presentations/Null-References-The-Billion-Dollar-Mistake-Tony-Hoare>,
	referenced 27 February 2019. 

\[Odersky 2014\]: 
:   Martin Odersky. *Scala by Example*,
	EPFL, 2014. Available at 
	<https://www.scala-lang.org/docu/files/ScalaByExample.pdf>.

\[Odersky 2016\]: 
:   Martin Odersky, Lex Spoon, and Bill Venners.
    *Programming in Scala*, 3rd Edition, Artima Inc, 2016;
	1st Edition, 2007; 2nd Edition, 2010.

\[SourceMaking 2019\]:
:   SourceMaking. Null Object Design Pattern, *Design Patterns*,
    Available at
    <https://sourcemaking.com/design\_patterns/null\_object>,
	referenced 27 February 2019. 

\[Wikipedia 2019\]:
:   Wikipedia. Articles on 
    [Null Object Pattern 
	](<https://en.wikipedia.org/wiki/Null\_object\_pattern>)
	Nullable Type
	](<https://en.wikipedia.org/wiki/Nullable\_type>),
	accessed 28 February 2019.

\[Woolf 1998\]:
:   Bobby Woolf. Null Object, Chapter 1, In, Robert Martin, Dirk Riehle,
    and Frank Buschmann, editors, *Pattern Languages of Program Design
    3*, Addison Wesley Longman, 1998.


## Terms and Concepts

*Big idea*: Using ordinary data values to represent failures and
exceptions in programs. This preserves referential transparency and
type safety while also preserving the benefit of exception-handling
mechanisms, that is, the consolidation of error-handling logic.
    
*Concepts*: Error handling, exceptions referential transparency, type
safety, null reference, Null Object design pattern, option types,
nullabile types, `Option`{.scala} and `Either`{.scala} algebraic data
types in Scala, method chaining, type variance, covariant and
contravariant, parameter passing (by-value, by-name), thunk, free
variables, closure, strict and nonstrict parameters/functions, eager
and lazy evaluation, follow the types to implementation (type-driven
development), lifting, for-comprehensions, syntactic sugar,
(generators, definitions, guards), desugaring.
