:1: error: identifier expected but '(' found.
175 | "hi there!".(0)
176 | ```
177 |
178 |
188 |
--------------------------------------------------------------------------------
/src/pages/intro/literals.md:
--------------------------------------------------------------------------------
1 | ## Literal Objects
2 |
3 | We have already covered some of Scala's basic types. In this section we're going to round out that knowledge by covering all of Scala's *literal expressions*. A literal expression represents a fixed value that stands "for itself". Here's an example:
4 |
5 | ```tut:book
6 | 42
7 | ```
8 |
9 | This interaction at the REPL shows us that the literal `42` evaluates to the `Int` `42`.
10 |
11 | Don't confuse a literal with the value it evaluates to! The literal expression is the representation in the program text before the program is run, and the value is the representation in the computer's memory after the program has run.
12 |
13 | If you have prior programming experience, particularly Java experience, the literals in Scala should be familiar to you.
14 |
15 | ### Numbers
16 |
17 | Numbers share the same types available in Java: `Int` for 32-bit integers, `Double` for 64-bit floating point, `Float` for 32-bit floating point, and `Long` for 64-bit integers.
18 |
19 | ```tut:book
20 | 42
21 | 42.0
22 | 42.0f
23 | 42L
24 | ```
25 |
26 | Scala also has 16-bit `Short` integers and 8-bit `Byte`s, but there is no literal syntax for creating them. Instead, we create them using methods called `toShort` and `toByte`.
27 |
28 | ### Booleans
29 |
30 | Booleans are exactly the same as Java: `true` or `false`.
31 |
32 | ```tut:book
33 | true
34 | false
35 | ```
36 |
37 | ### Characters
38 |
39 | `Chars` are 16-bit Unicode values written as a single character enclosed in single quotes.
40 |
41 | ```tut:book
42 | 'a'
43 | ```
44 |
45 |
46 | #### Scala vs Java's Type Hierarchy {-}
47 |
48 | Although they are written with initial capitals, Scala's `Int`, `Double`, `Float`, `Long`, `Short`, `Byte`, `Boolen` and `Char` refer to exactly the same things as `int`, `double`, `float`, `long`, `short`, `byte`, `boolean`, and `char` in Java.
49 |
50 | In Scala all of these types act like objects with methods and fields. However, once your code is compiled, a Scala `Int` is exactly the same as a Java `int`. This makes interoperability between the two languages a breeze.
51 |
52 |
53 | ### Strings
54 |
55 | Strings are exactly Java's strings, and are written the same way.
56 |
57 | ```tut:book
58 | "this is a string"
59 | "the\nusual\tescape characters apply"
60 | ```
61 |
62 | ### Null
63 |
64 | Null is the same as Java, though not used nearly as often. Scala's `null` also has its own type: `Null`.
65 |
66 | ```tut:book
67 | null
68 | ```
69 |
70 |
71 | #### Using Nulls in Scala {-}
72 |
73 | Although `null`s are common in Java code, they are considered very bad practice in Scala.
74 |
75 | The main use of `null` in Java is to implement *optional* values that have some or no value at different points of a program's execution. However, `null` values cannot be checked by the compiler, leading to possible runtime errors in the form of `NullPointerExceptions`.
76 |
77 | Later we will see that Scala has the means to define optional values that *are* checked by the compiler. This removes the necessity of using `null`, making our programs much safer.
78 |
79 |
80 | ### Unit
81 |
82 | Unit, written `()`, is the Scala equivalent of Java's `void`. Unit is the result of expressions that evaluate to no interesting value, such as printing to standard output using `println`. The console doesn't print unit but we can ask for the type of an expression to see that unit is in fact the result of some expressions.
83 |
84 | ```tut:book
85 | ()
86 | ```
87 |
88 | ```scala
89 | :type ()
90 | // Unit
91 | ```
92 |
93 | ```tut:book
94 | println("something")
95 | ```
96 |
97 | ```scala
98 | :type println("something")
99 | // Unit
100 | ```
101 |
102 | Unit is an important concept in Scala. Many of Scala's syntactic constructs are *expressions* that have types and values. We need a placeholder for expressions that don't yield a useful value, and unit provides just that.
103 |
104 | ### Take home points
105 |
106 | In this section we have seen *literal* expressions, which evaluate to basic data types. These basics types are mostly identical to Java, except for `Unit` which has no equivalent.
107 |
108 | We note that every literal expression has a *type*, and evaluates to a *value*---something which is also true for more complex Scala expressions.
109 |
110 | In the next section we will learn how to define our own object literals.
111 |
112 | ### Exercises
113 |
114 | #### Literally Just Literals
115 |
116 | What are the values and types of the following Scala literals?
117 |
118 | ```tut:book:silent
119 | 42
120 |
121 | true
122 |
123 | 123L
124 |
125 | 42.0
126 | ```
127 |
128 |
129 | `42` is an `Int`. `true` is a `Boolean`. `123L` is a `Long`. `42.0` is a `Double`.
130 |
131 | This exercise just gives you some experience using the Scala console or Worksheet.
132 |
133 |
134 | #### Quotes and Misquotes
135 |
136 | What is the difference between the following literals? What is the type and value of each?
137 |
138 | ```tut:book:silent
139 | 'a'
140 |
141 | "a"
142 | ```
143 |
144 |
145 | The first is a literal `Char` and the second is a literal `String`.
146 |
147 |
148 | #### An Aside on Side-Effects
149 |
150 | What is the difference between the following expressions? What is the type and value of each?
151 |
152 | ```tut:book:silent
153 | "Hello world!"
154 |
155 | println("Hello world!")
156 | ```
157 |
158 |
159 | The literal expression `"Hello world!"` evaluates to a `String` value. The expression `println("Hello world!")` evaluates to `Unit` and, as a side-effect, prints `"Hello world!"` on the console.
160 |
161 | This an important distinction between a program that evaluates to a value and a program that prints a value as a side-effect. The former can be used in a larger expression but the latter cannot.
162 |
163 |
164 | #### Learning By Mistakes
165 |
166 | What is the type and value of the following literal? Try writing it on the REPL or in a Scala worksheet and see what happens!
167 |
168 | ```scala
169 | 'Hello world!'
170 | ```
171 |
172 |
173 | You should see an error message. Take the time to read and get used to the error messages in your development environment---you'll see plenty more of them soon!
174 |
175 |
--------------------------------------------------------------------------------
/src/pages/traits/traits-as-mixins.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: page
3 | title: "This and That: Traits as Mixins"
4 | ---
5 |
6 | In the previous section we looked at categorising objects using a single set of traits. In this section we will look at objects that can simultaneously be categorised using several type hierarchies. In functional programming these are known as [product types][link-product-types]. In object oriented programming there is a related concept: [multiple inheritance][link-multiple-inheritance].
7 |
8 | ## Traits as Mixins
9 |
10 | We achieve composition in Scala by separating each component into its own trait and **mixing the traits we want to use** together to form classes.
11 |
12 | The syntax is to write `extends` for the first trait and `with` for each following trait: `A extends B with C with D`. For example, imagine the following model of staff and students at a university:
13 |
14 | ```tut:invisible
15 | trait Course
16 | ```
17 |
18 | ```tut:book:silent
19 | trait Person {
20 | def firstName: String
21 | def lastName: String
22 | }
23 |
24 | trait Student extends Person {
25 | def studentNumber: String
26 | def coursesTaken: Seq[Course] // a list of courses
27 | }
28 |
29 | trait Staff extends Person {
30 | def staffNumber: String
31 | def coursesTaught: Seq[Course] // a list of courses
32 | }
33 |
34 | trait TeachingAssistant extends Staff with Student
35 | ```
36 |
37 | In this example, `TeachingAssistent` ends up with all of the methods from `Person`, `Staff`, and `Student`.
38 |
39 | ## Is-a vs Has-a
40 |
41 | A trait or class is a subtype of every trait it extends. This means that if `A extends B`, `A` **is a** `B` and may be used wherever a `B` is expected. A `TeachingAssistant` is a `Staff` member, a `Student`, and a `Person` and can be treated as any of these types.
42 |
43 | Don't confuse an is-a relationship with a **has a** relationship. A book has a publisher but is not a publisher itself, so we would not mixin a `Publisher` trait to a `Book`.
44 |
45 | ## Overriding and Super Calls
46 |
47 | Traits and classes can mofidy the fields and methods they inherit from supertypes. We can use the `override` keyword to redefine an existing field or method, and use the `super` keyword to refer to the original definition that we are overriding. For example:
48 |
49 | ```tut:book:silent
50 | trait Person {
51 | def firstName: String
52 | def lastName: String
53 | def name = s"$firstName $lastName"
54 | }
55 |
56 | trait Veteran extends Person {
57 | def rank: String
58 | override def name = s"$rank ${super.name}"
59 | }
60 | ```
61 |
62 | ## Trait Linearization
63 |
64 | Overriding can lead to interesting interactions if we have many traits that each override a particular method. Consider the following code---what happens when we call `foo` on an instance of `Example`?
65 |
66 | ```tut:book:silent
67 | trait Fooable { def foo: String }
68 |
69 | trait A extends Fooable { override def foo: String = "A" }
70 | trait B extends Fooable { override def foo: String = "B" }
71 | trait C extends Fooable { override def foo: String = "C" }
72 |
73 | case class Example() extends A with B with C
74 | ```
75 |
76 | The simple way to tell is to ask the REPL:
77 |
78 | ```
79 | scala> Example().foo
80 | res1: String = C
81 | ```
82 |
83 | Ambiguity between traits is resolved using **linearization**. They are effectively stacked on top of one another and any method call is resolved by searchin up the stack until a matching definition is found. In the example the search order imposed by linearization is `Example -> C -> B -> A -> AnyRef -> Any` (extending `AnyRef` is implicit when you don't explicitly `extend` anything else).
84 |
85 | Linearization enables us to come up with all sorts of byzantine designs where traits add pieces of behaviour to a few common methods. The simple rule of designing with linearization is: don't. **If you depend on the order in which traits are stacked, you are doing something wrong**---it is a sure way to introduce bugs into your code.
86 |
87 | ## Take home points
88 |
89 | We can model **multiple inheritance** in Scala by **mixing traits** with one another using the `with` keyword.
90 |
91 | Traits solve the method resolution problems of multiple inheritance by defining a **linearization order** that dictates the order of overriding. The linearization order is tied to the order of traits in the header of a class.
92 |
93 | **If you find yourself relying on the linearization order in your type heirarchy, stop!** That way madness lies.
94 |
95 | Multiple inheritance is one way (but not the only way) of modelling a **this and that** relationship between types. In functional programming, this is called a **product type**.
96 |
97 | We can also model product types using *generics*---we'll see these later.
98 |
99 | ## Exercises
100 |
101 | ### Perplexing publications
102 |
103 | Let's create a simple model for publisher data. Code a set of traits and classes according to the following description:
104 |
105 | - A *publication* is a *book* or a *periodical*.
106 |
107 | - A *book* has an *author* while a *periodical* has an *editor*.
108 |
109 | - *Periodicals* have many *issues*, each of which has a *volume* and an *issue number*.
110 |
111 | - A *manuscript* is a document of a certain *length* written by an *author*.
112 |
113 | - A *book* is a *manuscript*, but an *issue* of a periodical contains a sequence of *manuscripts*.
114 |
115 | Tip: a sequence of type `A` has type `Seq[A]`.
116 |
117 |
118 | This is as much a problem of parsing the problem description as it is writing code. However, looking at the final Scala code it is easy to verify that all of the initial requirements hold:
119 |
120 | ```tut:invisible
121 | trait Issue
122 | ```
123 |
124 | ```tut:book:silent
125 | trait Publication {
126 | def title: String
127 | }
128 |
129 | trait Manuscript {
130 | def title: String
131 | def length: Int
132 | def author: String
133 | }
134 |
135 | case class Book(
136 | val title: String,
137 | val author: String,
138 | val length: Int
139 | ) extends Publication with Manuscript
140 |
141 | case class Periodical(
142 | val title: String,
143 | val editor: String,
144 | val issues: Seq[Issue]
145 | ) extends Publication
146 |
147 | case class Issue(
148 | volume: Int,
149 | issue: Int,
150 | manuscripts: Seq[Manuscript]
151 | )
152 | ```
153 |
154 |
--------------------------------------------------------------------------------
/src/pages/classes/pattern-matching.md:
--------------------------------------------------------------------------------
1 | ## Pattern Matching
2 |
3 | Until now we have interacted with objects by calling methods or accessing fields. With case classes we can interact in another way, via *pattern matching*.
4 |
5 | Pattern matching is like an extended `if` expression that allows us to evaluate an expression depending on the "shape" of the data. Recall the `Person` case class we've seen in previous examples:
6 |
7 | ```tut:book:silent
8 | case class Person(firstName: String, lastName: String)
9 | ```
10 |
11 | Now imagine we wanted to implement a `Stormtrooper` that is looking for members of the rebellion. We could use pattern matching like this:
12 |
13 | ```tut:book:silent
14 | object Stormtrooper {
15 | def inspect(person: Person): String =
16 | person match {
17 | case Person("Luke", "Skywalker") => "Stop, rebel scum!"
18 | case Person("Han", "Solo") => "Stop, rebel scum!"
19 | case Person(first, last) => s"Move along, $first"
20 | }
21 | }
22 | ```
23 |
24 | Notice the syntax for a pattern (`Person("Luke", "Skywalker")`) matches the syntax for constructing the object the pattern matches (`Person("Luke", "Skywalker")`).
25 |
26 | Here it is in use:
27 |
28 | ```tut:book
29 | Stormtrooper.inspect(Person("Noel", "Welsh"))
30 | Stormtrooper.inspect(Person("Han", "Solo"))
31 | ```
32 |
33 |
34 | #### Pattern Matching Syntax {-}
35 |
36 | The syntax of a pattern matching expression is
37 |
38 | ```scala
39 | expr0 match {
40 | case pattern1 => expr1
41 | case pattern2 => expr2
42 | ...
43 | }
44 | ```
45 |
46 | where
47 |
48 | - the expression `expr0` evaluates to the value we match;
49 | - the patterns, or *guards*, `pattern1`, `pattern2`, and so on are checked against this value in order; and
50 | - the right-hand side expression (`expr1`, `expr2`, and so on) of the first pattern that matches is evaluated[^compilation].
51 |
52 | Pattern matching is itself an expression and thus evaluates to a value---the value of the matched expression.
53 |
54 |
55 | [^compilation]: In reality patterns are compiled to a more efficient form than a sequence of tests, but the semantics are the same.
56 |
57 |
58 | ### Pattern Syntax
59 |
60 | Scala has an expressive syntax for writing patterns or guards. For case classes the pattern syntax matches the constructor syntax. Take the data
61 |
62 | ```tut:book
63 | Person("Noel", "Welsh")
64 | ```
65 |
66 | A pattern to match against the `Person` type is written
67 |
68 | ```scala
69 | Person(pat0, pat1)
70 | ```
71 |
72 | where `pat0` and `pat1` are patterns to match against the `firstName` and `lastName` respectively. There are four possible patterns we could use in place of `pat0` or `pat1`:
73 |
74 | 1. A name, which matches any value at that position and binds it to the given name. For example, the pattern `Person(first, last)` binds the name `first` to the value `"Noel"`, and the name `last` to the value `"Welsh"`.
75 |
76 | 2. An underscore (`_`), which matches any value and ignores it. For example, as Stormtroopers only care about the first name of ordinary citizens we could just write `Person(first, _)` to avoid binding a name to the value of the `lastName`.
77 |
78 | 3. A literal, which successfully matches only the value the literal respresents. So , for example, the pattern `Person("Han", "Solo")` matches the `Person` with first name `"Han"` and last name `"Solo"`.
79 |
80 | 4. Another case class using the same constructor style syntax.
81 |
82 | Note there is a lot more we can do with pattern matching, and pattern matching is actually extensible. We'll look at these features in a later section.
83 |
84 |
85 | ### Take Home Points
86 |
87 | Case classes allow a new form of interaction, called *pattern matching*. Pattern matching allows us to take apart a case class, and evaluate different expressions depending on what the case class contains.
88 |
89 | The syntax for pattern matching is
90 |
91 | ```scala
92 | expr0 match {
93 | case pattern1 => expr1
94 | case pattern2 => expr2
95 | ...
96 | }
97 | ```
98 |
99 | A pattern can be one of
100 |
101 | 1. a name, binding any value to that name;
102 | 2. an underscore, matching any value and ignoring it;
103 | 3. a literal, matching the value the literal denotes; or
104 | 4. a constructor-style pattern for a case class.
105 |
106 | ### Exercises
107 |
108 | #### Feed the Cats
109 |
110 | Define an object `ChipShop` with a method `willServe`. This method should accept a `Cat` and return true if the cat’s favourite food is chips, and false otherwise. Use pattern matching.
111 |
112 |
113 | We can start by writing the skeleton suggested by the problem text.
114 |
115 | ```tut:book:silent
116 | case class Cat(name: String, colour: String, food: String)
117 | ```
118 |
119 | ```scala
120 | object ChipShop {
121 | def willServe(cat: Cat): Boolean =
122 | cat match {
123 | case Cat(???, ???, ???) => ???
124 | }
125 | }
126 | ```
127 |
128 | As the return type is `Boolean` we know we need at least two cases, one for true and one for false. The text of the exercise tells us what they should be: cats that prefer chips, and all other cats. We can implement this with a literal pattern and an `_` pattern.
129 |
130 | ```tut:book:silent
131 | object ChipShop {
132 | def willServe(cat: Cat): Boolean =
133 | cat match {
134 | case Cat(_, _, "Chips") => true
135 | case Cat(_, _, _) => false
136 | }
137 | }
138 | ```
139 |
140 |
141 |
142 | #### Get Off My Lawn!
143 |
144 | In this exercise we're going to write a simulator of my Dad, the movie critic. It's quite simple: any movie directed by Clint Eastwood gets a rating 10.0, any movie directed by John McTiernan gets a 7.0, while any other movie gets a 3.0. Implement an object called `Dad` with a method `rate` which accepts a `Film` and returns a `Double`. Use pattern matching.
145 |
146 |
147 | ```scala
148 | object Dad {
149 | def rate(film: Film): Double =
150 | film match {
151 | case Film(_, _, _, Director("Clint", "Eastwood", _)) => 10.0
152 | case Film(_, _, _, Director("John", "McTiernan", _)) => 7.0
153 | case _ => 3.0
154 | }
155 | }
156 | ```
157 |
158 | Pattern matching is becoming quite verbose in this case. Later on we'll learn how we can use pattern matching to match a particular value, called a *constant pattern*.
159 |
160 |
--------------------------------------------------------------------------------
/src/pages/traits/modelling-data-with-traits.md:
--------------------------------------------------------------------------------
1 | ## Modelling Data with Traits
2 |
3 | In this section we're going to shift our focus from language features to programming patterns. We're going to look at modelling data and learn a process for expressing in Scala any data model defined in terms of *logical ors and ands*. Using the terminology of object-oriented programming, we will express *is-a* and *has-a* relationships. In the terminology of functional programming we are learning about *sum* and *product types*, which are together called *algebraic data types*.
4 |
5 | Our goal in this section is to see how to translate a data model into Scala code. In the next section we'll see patterns for code that uses algebraic data types.
6 |
7 | ### The Product Type Pattern
8 |
9 | Our first pattern is to model data that contains other data. We might describe this as "`A` *has a* `B` *and* `C`". For example, a `Cat` has a colour and a favourite food; a `Visitor` has an id and a creation date; and so on.
10 |
11 | The way we write this is to use a case class. We've already done this many times in exercises; now we're formalising the pattern.
12 |
13 |
14 | #### Product Type Pattern {-}
15 |
16 | If `A` has a `b` (with type `B`) and a `c` (with type `C`) write
17 |
18 | ```tut:invisible
19 | type A = Any
20 | type B = Any
21 | type C = Any
22 | type D = Any
23 | ```
24 |
25 | ```tut:book:silent
26 | case class A(b: B, c: C)
27 | ```
28 |
29 | or
30 |
31 | ```tut:book:silent
32 | trait A {
33 | def b: B
34 | def c: C
35 | }
36 | ```
37 |
38 |
39 | ## The Sum Type Pattern
40 |
41 | Our next pattern is to model data that is two or more distinct cases. We might describe this as "`A` *is a* `B` *or* `C`". For example, a `Feline` is a `Cat`, `Lion`, or `Tiger`; a `Visitor` is an `Anonymous` or `User`; and so on.
42 |
43 | We write this using the sealed trait / final case class pattern.
44 |
45 |
46 | #### Sum Type Pattern {-}
47 |
48 | If `A` is a `B` or `C` write
49 |
50 | ```tut:book:silent
51 | sealed trait A
52 | final case class B() extends A
53 | final case class C() extends A
54 | ```
55 |
56 |
57 | ### Algebraic Data Types
58 |
59 | An algebraic data type is any data that uses the above two patterns. In the functional programming literature, data using the "has-a and" pattern is known as a *product type*, and the "is-a or" pattern is a *sum type*.
60 |
61 | ### The Missing Patterns
62 |
63 | We have looked at relationships along two dimensions: is-a/has-a, and and/or. We can draw up a little table and see we only have patterns for two of the four table cells.
64 |
65 | +-----------+--------------+----------+
66 | | | And | Or |
67 | +===========+==============+==========+
68 | | **Is-a** | | Sum type |
69 | +-----------+--------------+----------+
70 | | **Has-a** | Product type | |
71 | +-----------+--------------+----------+
72 |
73 |
74 |
75 | What about the missing two patterns?
76 |
77 | The "is-a and" pattern means that `A` is a `B` and `C`. This pattern is in some ways the inverse of the sum type pattern, and we can implement it as
78 |
79 | ```tut:book:silent
80 | trait B
81 | trait C
82 | trait A extends B with C
83 | ```
84 |
85 | In Scala a trait can extend as many traits as we like using the `with` keyword like `A extends B with C with D` and so on. We aren't going to use this pattern in this course. If we want to represent that some data conforms to a number of different interfaces we will often be better off using a *type class*, which we will explore later. There are, however, several legitimate uses of this pattern:
86 |
87 | - for modularity, using what's known as the [cake pattern](http://jonasboner.com/real-world-scala-dependency-injection-di/); and
88 | - sharing implementation across several classes where it doesn't make sense to make default implementations in the main trait.
89 |
90 | The "has-a or" patterns means that `A` has a `B` or `C`. There are two ways we can implement this. We can say that `A` has a `d` of type `D`, where `D` is a `B` or `C`. We can mechanically apply our two patterns to implement this:
91 |
92 | ```tut:book:silent
93 | trait A {
94 | def d: D
95 | }
96 | sealed trait D
97 | final case class B() extends D
98 | final case class C() extends D
99 | ```
100 |
101 | Alternatively we could implement this as `A` is a `D` or `E`, and `D` has a `B` and `E` has a `C`. Again this translates directly into code
102 |
103 | ```tut:book:silent
104 | sealed trait A
105 | final case class D(b: B) extends A
106 | final case class E(c: C) extends A
107 | ```
108 |
109 | ### Take Home Points
110 |
111 | We have seen that we can mechanically translate data using the "has-a and" and "is-a or" patterns (or, more succinctly, the product and sum types) into Scala code. This type of data is known as an algebraic data type. Understanding these patterns is very important for writing idiomatic Scala code.
112 |
113 | ### Exercises
114 |
115 | #### Stop on a Dime
116 |
117 | A traffic light is red, green, or yellow. Translate this description into Scala code.
118 |
119 |
120 | This is a direct application of the sum type pattern.
121 |
122 | ```tut:book:silent
123 | sealed trait TrafficLight
124 | case object Red extends TrafficLight
125 | case object Green extends TrafficLight
126 | case object Yellow extends TrafficLight
127 | ```
128 |
129 | As there are no fields or methods on the three cases, and thus there is no need to create more than one instance of them, I used case objects instead of case classes.
130 |
131 |
132 | #### Calculator
133 |
134 | A calculation may succeed (with an `Int` result) or fail (with a `String` message). Implement this.
135 |
136 |
137 | ```tut:book:silent
138 | sealed trait Calculation
139 | final case class Success(result: Int) extends Calculation
140 | final case class Failure(reason: String) extends Calculation
141 | ```
142 |
143 |
144 | #### Water, Water, Everywhere
145 |
146 | Bottled water has a size (an `Int`), a source (which is a well, spring, or tap), and a `Boolean` carbonated. Implement this in Scala.
147 |
148 |
149 | Crank the handle on the product and sum type patterns.
150 |
151 | ```tut:book:silent
152 | sealed trait Source
153 | case object Well extends Source
154 | case object Spring extends Source
155 | case object Tap extends Source
156 | final case class BottledWater(size: Int, source: Source, carbonated: Boolean)
157 | ```
158 |
159 |
--------------------------------------------------------------------------------
/src/pages/fp/ho-functions.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: page
3 | title: Higher-Order Functions
4 | ---
5 |
6 | A **higher-order function** is a function that accepts another function. We have seen several uses already, particularly with collections. Here we're going to use higher-order functions in some novel situations, with the aim of solidifying our understanding. This section will be heavy on the examples.
7 |
8 | We're going to spend a lot of time with Scala's `List` type, so a quick overview:
9 |
10 | * A `List[A]` is either `Nil` (the empty list) or a pair `::(a: A, as: List[A])`
11 | * You can write the pair constructor using infix syntax `a :: as`.
12 | * You can pattern match on the two cases as they are both case classes.
13 |
14 | A `List` is built recursively. For example, given the empty list we can prepend an element like so:
15 |
16 | ```scala
17 | scala> 1 :: Nil
18 | res17: List[Int] = List(1)
19 | ```
20 |
21 | We can build longer lists in the same way.
22 |
23 | ```scala
24 | scala> 1 :: (2 :: Nil)
25 | res19: List[Int] = List(1, 2)
26 | ```
27 |
28 | As `::` is right associative we can drop the brackets.
29 |
30 | ```scala
31 | scala> 1 :: 2 :: Nil
32 | res20: List[Int] = List(1, 2)
33 | ```
34 |
35 | ## Spinning Wheels
36 |
37 | Write a method that copies a `List`.
38 |
39 | Hint: A `List` is `::` or `Nil`. Remember how we learned to deal with sum types?
40 |
41 |
42 | ```scala
43 | def copy(in: List[Int]): List[Int] =
44 | in match {
45 | case Nil => Nil
46 | case (x :: xs) => x :: copy(xs)
47 | }
48 | ```
49 |
50 |
51 | This is a simple function that illustrates how the shape of the code follows the shape of the data. A list has two cases, and so does our method. Notice how the individual cases follow the shape of the data. `Nil` goes to `Nil`. The pair (`::`) goes to a pair with a recursive call to `copy`.
52 |
53 | ## A Map of the Territory
54 |
55 | Write a method to add one to all the elements of `List[Int]`. Don't use any methods defined on `List` to do so.
56 |
57 |
58 | ```scala
59 | def addOne(in: List[Int]): List[Int] =
60 | in match {
61 | case Nil => Nil
62 | case (x :: xs) => (x + 1) :: addOne(xs)
63 | }
64 | ```
65 |
66 |
67 | Alter your method to accept any `Int => Int` function.
68 |
69 |
70 | ```scala
71 | def map(f: Int => Int, in: List[Int]): List[Int] =
72 | in match {
73 | case Nil => Nil
74 | case (x :: xs) => f(x) :: map(f, xs)
75 | }
76 | ```
77 |
78 |
79 | Make your function generic in the type of the `List`.
80 |
81 |
82 | ```scala
83 | def map[A](f: A => A, in: List[A]): List[A] =
84 | in match {
85 | case Nil => Nil
86 | case (x :: xs) => f(x) :: map(f, xs)
87 | }
88 | ```
89 |
90 |
91 | There are a few concepts in this example. The first is the idea of the passing functions as reusable computations. We've already seen in the section on collections the benefits this brings.
92 |
93 | More interesting is the similarity of this code to the code for `copy` above. Notice once again the pattern: two cases to match the two cases of `List`, and the computation follows the shape of the data.
94 |
95 | ## Folding Up the Map
96 |
97 | Write a method to sum up the elements of `List[Int]`. Don't use any methods defined on `List` to do so.
98 |
99 |
100 | ```scala
101 | def sum(in: List[Int]): Int =
102 | in match {
103 | case Nil => 0
104 | case (x :: xs) => x + sum(xs)
105 | }
106 | ```
107 |
108 |
109 | Now generalise your method to accept any function `(Int, Int) => Int` in place of addition. You'll need to make another change, but I'll leave you work out what that is.
110 |
111 |
112 | ```scala
113 | def accumulate(f: (Int, Int) => Int, zero: Int, in: List[Int]): Int =
114 | in match {
115 | case Nil => zero
116 | case (x :: xs) => f(x, accumulate(xs))
117 | }
118 | ```
119 |
120 |
121 | Now generalise your method to be generic over the type of `List`. What is this function conventionally called?
122 |
123 |
124 | ```scala
125 | def foldRight[A, B](f: (A, B) => B, zero: B, in: List[A]): B =
126 | in match {
127 | case Nil => zero
128 | case (x :: xs) => f(x, foldRight(f, zero, xs))
129 | }
130 | ```
131 |
132 |
133 | Notice it's the same pattern again, though slightly generalised from before!
134 |
135 |
136 | ## Calculus the Easy Way (Optional)
137 |
138 | You perhaps encountered differentiation in school. When we differentiate a function we create another function that calculates it's rate of change, called its derivative. In many cases we can do this symbolically, but we're going to do it the CS way---numerically.
139 |
140 | Implement a function `derivative` that takes a function `Double => Double` and returns the derivative (also `Double => Double`).
141 |
142 | Hint 1: We can approximate the derivative by calculating the *centered difference* `(f(x + h) - f(x - h)) / 2h` for small `h`.
143 |
144 | Hint 2: The `math` package contains several useful methods such as `abs`. Note the derivative of `math.exp(x)` is itself, and the derivative of `math.sin` is `math.cos`. You can use these properties to test your function.
145 |
146 |
147 | ```scala
148 | def derivative(f: Double => Double): Double => Double = {
149 | val h = 0.01
150 | (x: Double) =>
151 | (f(x + h) - f(x - h)) / (2 * h)
152 | }
153 | ```
154 |
155 |
156 | Choosing a fixed value of `h` is not always a good idea. Make a function `makeDerivative` that allows you to set the value of `h` and returns `derivative`.
157 |
158 |
159 | ```scala
160 | def makeDerivative(h: Double) = {
161 | val derivative = (f: Double => Double) =>
162 | (x: Double) =>
163 | (f(x + h) - f(x - h)) / (2 * h)
164 | derivative
165 | }
166 | ```
167 |
168 |
169 | Now we can adjust `h` till we have calculated `derivative` at a point to within a given tolerance. Write a function `solve` that solves the derivative of a function at a point to within a given tolerance.
170 |
171 |
172 | ```scala
173 | def solve(f: Double => Double, x: Double, tolerance: Double) = {
174 | def iterate(bracket: Double, lastGuess: Double): Double = {
175 | val guess = makeDerivative(bracket)(f)(x)
176 | if(math.abs(guess - lastGuess) < tolerance)
177 | lastGuess
178 | else
179 | iterate(bracket / 2, guess)
180 | }
181 |
182 | iterate(0.05, makeDerivative(0.1)(f)(x))
183 | }
184 | ```
185 |
186 |
--------------------------------------------------------------------------------
/src/pages/intro/expressions.md:
--------------------------------------------------------------------------------
1 | ## Compound Expressions
2 |
3 | We have almost finished our basic introduction to Scala. In this section we are going to look at two special kinds of expressions, *conditionals* and *blocks*, we will need in more complicated programs.
4 |
5 | ### Conditionals
6 |
7 | A conditional allows us to choose an expression to evaluate based on some condition. For example, we can choose a string based on which of two numbers is the smallest.
8 |
9 | ```tut:book
10 | if(1 < 2) "Yes" else "No"
11 | ```
12 |
13 |
14 | #### Conditionals are Expressions {-}
15 |
16 | Scala's `if` statement has the same syntax as Java's. One important difference is that *Scala's conditional is an expression*---it has a type and returns a value.
17 |
18 |
19 | The expression that is not selected does not get evaluated. This is apparent if we use an expression with a side-effect.
20 |
21 | ```tut:book
22 | if(1 < 2) println("Yes") else println("No")
23 | ```
24 |
25 | We can tell the expression `println("No")` is not evaluated because `No` is not output to the console.
26 |
27 |
28 | #### Conditional Expression Syntax {-}
29 |
30 | The syntax for a conditional expression is
31 |
32 | ```scala
33 | if(condition)
34 | trueExpression
35 | else
36 | falseExpression
37 | ```
38 |
39 | where
40 |
41 | - `condition` is an expression with `Boolean` type;
42 | - `trueExpression` is the expression evaluated if `condition` evaluates to `true`; and
43 | - `falseExpression` is the expression evaluated if `condition` evaluates to `false`.
44 |
45 |
46 |
47 | ### Blocks
48 |
49 | Blocks are expressions that allow us to sequence computations together. They are written as a pair of braces containing sub-expressions separated by semicolons or newlines.
50 |
51 | ```tut:book:fail
52 | { 1; 2; 3 }
53 | ```
54 |
55 | As you can see, executing this code causes the console to raise a number of warnings and return the `Int` value `3`.
56 |
57 | A block is a sequence of expressions or declarations surrounded by braces. A block is also an expression: it executes each of its sub-expressions in order and returns the value of the last expression.
58 |
59 | Why execute `1` and `2` if we're going to throw their values away? This is a good question, and is the reason the Scala compiler raised those warnings above.
60 |
61 | One reason to use a block is to use code that produces side-effects before calculating a final value:
62 |
63 | ```tut:book
64 | {
65 | println("This is a side-effect")
66 | println("This is a side-effect as well")
67 | 3
68 | }
69 | ```
70 |
71 | We can also use a block when we want to name intermediate results, such as
72 |
73 | ```tut:book:silent
74 | def name: String = {
75 | val title = "Professor"
76 | val name = "Funkenstein"
77 | title + " " + name
78 | }
79 | ```
80 |
81 | ```tut:book
82 | name
83 | ```
84 |
85 |
86 |
87 | #### Block Expression Syntax {-}
88 |
89 | The syntax of a block expression is
90 |
91 | ```scala
92 | {
93 | declarationOrExpression ...
94 | expression
95 | }
96 | ```
97 |
98 | where
99 |
100 | - the optional `declarationOrExpression`s are declarations or expression; and
101 | - `expression` is an expression determining the type and value of the block expression.
102 |
103 |
104 | ### Take home points
105 |
106 | Conditional expressions allow us to choose an expression to evaluate based on a `Boolean` condition. The syntax is
107 |
108 | ```scala
109 | if(condition)
110 | trueExpression
111 | else
112 | falseExpression
113 | ```
114 |
115 | A conditional, being an expression, has a type and evaluates to an object.
116 |
117 |
118 | A block allows us to sequence expressions and declarations. It is commonly used when we want to sequence expressions with side-effects, or name intermediate results in a computation. The syntax is
119 |
120 | ```scala
121 | {
122 | declarationOrExpression ...
123 | expression
124 | }
125 | ```
126 |
127 | The type and value of a block is that of the last expression in the block.
128 |
129 |
130 | ### Exercises
131 |
132 | #### A Classic Rivalry
133 |
134 | What is the type and value of the following conditional?
135 |
136 | ```tut:book:silent
137 | if(1 > 2) "alien" else "predator"
138 | ```
139 |
140 |
141 | It's a `String` with value `"predator"`. Predators are clearly best:
142 |
143 | ```tut:book
144 | if(1 > 2) "alien" else "predator"
145 | ```
146 |
147 | The type is determined by the upper bound of the types in the *then* and *else* expressions. In this case both expressions are `Strings` so the result is also a `String`.
148 |
149 | The value is determined at runtime. `2` is greater than `1` so the conditional evaluates to the value of the *else* expression.
150 |
151 |
152 | #### A Less Well Known Rivalry
153 |
154 | What about this conditional?
155 |
156 | ```tut:book:silent
157 | if(1 > 2) "alien" else 2001
158 | ```
159 |
160 |
161 | It's a value of type `Any` with value `2001`:
162 |
163 | ```tut:book
164 | if(1 > 2) "alien" else 2001
165 | ```
166 |
167 | This is similar to the previous exercise---the difference is the type of the result. We saw earlier that the type is the *upper bound* of the positive and negative arms of the expression. `"alien"` and `2001` are completely different types - their closest common ancestor is `Any`, which is the grand supertype of all Scala types.
168 |
169 | This is an important observation: types are determined at compile time, before the program is run. The compiler doesn't know which of `1` and `2` is greater before running the program, so it can only make a best guess at the type of the result of the conditional. `Any` is as close as it can get in this program, whereas in the previous exercise it can get all the way down to `String`.
170 |
171 | We'll learn more about `Any` in the following sections. Java programmers shouldn't confuse it with `Object` because it subsumes value types like `Int` and `Boolean` as well.
172 |
173 |
174 | #### An if Without an else
175 |
176 | What about this conditional?
177 |
178 | ```tut:book:silent
179 | if(false) "hello"
180 | ```
181 |
182 |
183 | The result type and value are `Any` and `()` respectively:
184 |
185 | ```tut:book
186 | if(false) "hello"
187 | ```
188 |
189 | All code being equal, conditionals without `else` expressions only evaluate to a value half of the time. Scala works around this by returning the `Unit` value if the `else` branch should be evaluated. We would usually only use these expressions for their side-effects.
190 |
191 |
--------------------------------------------------------------------------------
/src/pages/implicits/json.md:
--------------------------------------------------------------------------------
1 | ## JSON Serialisation
2 |
3 | In this section we have an extended example involving serializing Scala data to JSON, which is one of the classic use cases for type classes. The typical process for converting data to JSON in Scala involves two steps. First we convert our data types to an intermediate case class representation, then we serialize the intermediate representation to a string.
4 |
5 | Here is a suitable case class representation of a subset of the JSON language. We have a `sealed trait JsValue` that defines a `stringify` method, and a set of subtypes for two of the main JSON data types---objects and strings:
6 |
7 | ```tut:book:silent
8 | sealed trait JsValue {
9 | def stringify: String
10 | }
11 |
12 | final case class JsObject(values: Map[String, JsValue]) extends JsValue {
13 | def stringify = values
14 | .map { case (name, value) => "\"" + name + "\":" + value.stringify }
15 | .mkString("{", ",", "}")
16 | }
17 |
18 | final case class JsString(value: String) extends JsValue {
19 | def stringify = "\"" + value.replaceAll("\\|\"", "\\\\$1") + "\""
20 | }
21 | ```
22 |
23 | You should recognise this as the algebraic data type pattern.
24 |
25 | We can construct JSON objects and serialize them as follows:
26 |
27 | ```tut:book
28 | val obj = JsObject(Map("foo" -> JsString("a"), "bar" -> JsString("b"), "baz" -> JsString("c")))
29 |
30 | obj.stringify
31 | ```
32 |
33 | ### Convert X to JSON
34 |
35 | Let's create a type class for converting Scala data to JSON. Implement a `JsWriter` trait containing a single abstract method `write` that converts a value to a `JsValue`.
36 |
37 |
38 | The *type class* is generic in a type `A`. The `write` method converts a value of type `A` to some kind of `JsValue`.
39 |
40 | ```tut:book:silent
41 | trait JsWriter[A] {
42 | def write(value: A): JsValue
43 | }
44 | ```
45 |
46 |
47 | Now let's create the dispatch part of our type class. Write a `JsUtil` object containing a single method `toJson`. The method should accept a value of an arbitrary type `A` and convert it to JSON.
48 |
49 | Tip: your method will have to accept an implicit `JsWriter` to do the actual conversion.
50 |
51 |
52 | ```tut:book:silent
53 | object JsUtil {
54 | def toJson[A](value: A)(implicit writer: JsWriter[A]) =
55 | writer write value
56 | }
57 | ```
58 |
59 |
60 | Now, let's revisit our data types from the web site visitors example in the [Sealed traits](/traits/sealed-traits.html) section:
61 |
62 | ```tut:book:silent
63 | import java.util.Date
64 |
65 | sealed trait Visitor {
66 | def id: String
67 | def createdAt: Date
68 | def age: Long = new Date().getTime() - createdAt.getTime()
69 | }
70 |
71 | final case class Anonymous(
72 | id: String,
73 | createdAt: Date = new Date()
74 | ) extends Visitor
75 |
76 | final case class User(
77 | id: String,
78 | email: String,
79 | createdAt: Date = new Date()
80 | ) extends Visitor
81 | ```
82 |
83 | Write `JsWriter` instances for `Anonymous` and `User`.
84 |
85 |
86 | ```tut:book:silent
87 | implicit object AnonymousWriter extends JsWriter[Anonymous] {
88 | def write(value: Anonymous) = JsObject(Map(
89 | "id" -> JsString(value.id),
90 | "createdAt" -> JsString(value.createdAt.toString)
91 | ))
92 | }
93 |
94 | implicit object UserWriter extends JsWriter[User] {
95 | def write(value: User) = JsObject(Map(
96 | "id" -> JsString(value.id),
97 | "email" -> JsString(value.email),
98 | "createdAt" -> JsString(value.createdAt.toString)
99 | ))
100 | }
101 | ```
102 |
103 |
104 | Given these two definitions we can implement a `JsWriter` for `Visitor` as follows. This uses a new type of pattern -- `a: B` -- which matches any value of type `B` and binds it to a variable `a`:
105 |
106 | ```tut:book:silent
107 | implicit object VisitorWriter extends JsWriter[Visitor] {
108 | def write(value: Visitor) = value match {
109 | case anon: Anonymous => JsUtil.toJson(anon)
110 | case user: User => JsUtil.toJson(user)
111 | }
112 | }
113 | ```
114 |
115 | Finally, verify that your code works by converting the following list of users to JSON:
116 |
117 | ```tut:book:silent
118 | val visitors: Seq[Visitor] = Seq(Anonymous("001", new Date), User("003", "dave@xample.com", new Date))
119 | ```
120 |
121 |
122 | ```tut:book:silent
123 | visitors.map(visitor => JsUtil.toJson(visitor))
124 | ```
125 |
126 |
127 | ### Prettier Conversion Syntax
128 |
129 | Let's improve our JSON syntax by combining type classes and type enrichment. Convert `JsUtil` to an `implicit class` with a `toJson` method. Sample usage:
130 |
131 | ```scala
132 | Anonymous("001", new Date).toJson
133 | ```
134 |
135 |
136 | ```tut:book:silent
137 | implicit class JsUtil[A](value: A) {
138 | def toJson(implicit writer: JsWriter[A]) =
139 | writer write value
140 | }
141 | ```
142 |
143 | In the previous exercise we only defined `JsWriters` for our main case classes. With this convenient syntax, it makes sense for us to have an complete set of `JsWriters` for all the serializable types in our codebase, including `Strings` and `Dates`:
144 |
145 | ```tut:book:silent
146 | implicit object StringWriter extends JsWriter[String] {
147 | def write(value: String) = JsString(value)
148 | }
149 |
150 | implicit object DateWriter extends JsWriter[Date] {
151 | def write(value: Date) = JsString(value.toString)
152 | }
153 | ```
154 |
155 | With these definitions we can simplify our existing `JsWriters` for `Anonymous`, `User`, and `Visitor`:
156 |
157 | ```tut:invisible
158 | // I must repeat this here for some reason or the implicit resolution in the block below fails
159 | implicit class JsUtil[A](value: A) {
160 | def toJson(implicit writer: JsWriter[A]) =
161 | writer write value
162 | }
163 | ```
164 |
165 | ```tut:book:silent
166 | implicit object AnonymousWriter extends JsWriter[Anonymous] {
167 | def write(value: Anonymous) = JsObject(Map(
168 | "id" -> value.id.toJson,
169 | "createdAt" -> value.createdAt.toJson
170 | ))
171 | }
172 |
173 | implicit object UserWriter extends JsWriter[User] {
174 | def write(value: User) = JsObject(Map(
175 | "id" -> value.id.toJson,
176 | "email" -> value.email.toJson,
177 | "createdAt" -> value.createdAt.toJson
178 | ))
179 | }
180 |
181 | implicit object VisitorWriter extends JsWriter[Visitor] {
182 | def write(value: Visitor) = value match {
183 | case anon: Anonymous => anon.toJson
184 | case user: User => user.toJson
185 | }
186 | }
187 | ```
188 |
189 |
--------------------------------------------------------------------------------
/src/pages/implicits/implicit-resolution.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: page
3 | title: Implicit Resolution
4 | ---
5 |
6 | ## Implicit Resolution Rules
7 |
8 | Scala has three types of implicits---implicit classes, implicit values, and implicit conversions. Each works in the same way---the compiler detects a type error in our code, locates a matching implicit, and applies it to fix the error. This is a powerful mechanism, but we need to control it very carefully to prevent the compiler changing our code in ways we don't expect. For this reason, there is a strict set of **implicit resolution rules** that we can use to dictate the compiler's behaviour:
9 |
10 | 1. **Explicits first rule**---if the code already type checks, the compiler ignores implicits altogether;
11 | 2. **Marking rule**---the compiler only uses definitions marked with the `implicit` keyword;
12 | 3. **Scope rule**---the compiler only uses definitions that are *in scope* at the current location in the code (see below);
13 | 4. **Non-ambiguity rule**---the compiler only applies an implicit if it is the only candidate available;
14 | 5. **One-at-a-time rule**---the compiler never chains implicits together to fix type errors---doing so would drastically increase compile times;
15 |
16 | Note that the name of the implicit doesn't come into play in this process.
17 |
18 | ### Implicit Scope
19 |
20 | The *scope rule* of implicit resolution uses a special set of scoping rules that allow us to package implicits in useful ways. These rules, collectively referred to as **implicit scope**, form a search path that the compiler uses to locate implicits:
21 |
22 | 1. **Local scope**---First look locally for any identifier that is tagged as `implicit`. This must be a single identifier (i.e. `a`, not `a.b`), and can be defined locally or in the surrounding class, object, or trait, or `imported` from elsewhere.
23 |
24 | 2. **Companion objects**---If an implicit cannot be found locally, the compiler looks in the companion objects of types involved in the type error. Will see more of this rule in the next section.
25 |
26 | ## Packaging Implicit Values
27 |
28 | Implicits **cannot be defined at the top level** (except in the Scala console). They must be wrapped in an outer trait, class, or singleton object. The typical way of packaging an implicit value is to define it inside a trait called `SomethingImplicits` and extend that trait to create a singleton of the same name:
29 |
30 | ```tut:book:silent
31 | trait VowelImplicits {
32 | implicit class VowelOps(str: String) {
33 | val vowels = Seq('a', 'e', 'i', 'o', 'u')
34 | def numberOfVowels =
35 | str.toList.filter(vowels contains _).length
36 | }
37 | }
38 |
39 | object VowelImplicits extends VowelImplicits
40 | ```
41 |
42 | This gives developers two convenient ways of using our code:
43 |
44 | 1. quickly bring our implicit into scope via the singleton object using an `import`:
45 |
46 | ```tut:book:silent
47 | // `VowelOps` is not in scope here
48 |
49 | def testMethod = {
50 | import VowelImplicits._
51 |
52 | // `VowelOps` is in scope here
53 |
54 | "the quick brown fox".numberOfVowels
55 | }
56 |
57 | // `VowelOps` is no longer in scope here
58 | ```
59 |
60 | 2. stack our trait with a set of other traits to produce a library of implicits that can be brought into scope using inheritance or an `import`:
61 |
62 | ```tut:invisible
63 | trait VowelImplicits
64 | trait MoreImplicits
65 | trait YetMoreImplicits
66 | ```
67 |
68 | ```tut:book:silent
69 | object AllTheImplicits extends VowelImplicits with MoreImplicits with YetMoreImplicits
70 |
71 | import AllTheImplicits._
72 |
73 | // `VowelOps` is in scope here
74 | // along with other implicit classes
75 | ```
76 |
77 |
78 | **Implicits tip:** Some Scala developers dislike implicits because they can be hard to debug. The reason for this is that an implicit definition at one point in our codebase can have an invisible affect on the meaning of a line of code written elsewhere.
79 |
80 | While this is a valid criticism of implicits, the solution is not to abandon them altogether but to apply strict design principles to regulate their use. Here are some tips:
81 |
82 | 1. Keep tight control over the scope of your implicits. Package them into traits and objects and only import them where you want to use them.
83 |
84 | 2. Package all your implicits in traits/objects with names ending in `Implicits`. This makes them easy to find using a global search across your codebase.
85 |
86 | 3. Only use implicits on specific types. Defining an implicit class on a general type like `Any` is more likely to cause problems than defining it on a specific type like `WebSiteVisitor`.
87 |
88 | The same resolution rules apply for implicit values as for implicit classes. If the compiler is unable to find suitable candidates for all parameters in the list, we get a compilation error.
89 |
90 | Let's redefine our adapters for `HtmlWriter` so we can bring them all into scope. Note that outside the REPL implicit values are subject to the same packaging restrictions as implicit classes---they have to be defined inside another class, object, or trait. We'll use the packaging convention we discussed in the previous section:
91 |
92 | ```tut:invisible
93 | trait HtmlWriter[A] {
94 | def write(a: A): String
95 | }
96 | case class Person(name: String, email: String)
97 | import java.util.Date
98 | ```
99 |
100 | ```tut:book:silent
101 | object wrapper {
102 | trait HtmlImplicits {
103 | implicit object PersonWriter extends HtmlWriter[Person] {
104 | def write(person: Person) =
105 | s"
${person.name} <${person.email}>"
106 | }
107 |
108 | implicit object DateWriter extends HtmlWriter[Date] {
109 | def write(in: Date) = s"
${in.toString}"
110 | }
111 | }
112 |
113 | object HtmlImplicits extends HtmlImplicits
114 | }; import wrapper._
115 | ```
116 |
117 | ```tut:invisible
118 | object HtmlUtil {
119 | def htmlify[A](data: A)(implicit writer: HtmlWriter[A]): String = {
120 | writer.write(data)
121 | }
122 | }
123 | ```
124 |
125 | We can now use our adapters with `htmlify`:
126 |
127 | ```tut:book
128 | import HtmlImplicits._
129 |
130 | HtmlUtil.htmlify(Person("John", "john@example.com"))
131 | ```
132 |
133 | This version of the code has much lighter syntax requirements than its predecessor. We have now assembled the complete type class pattern: `HtmlUtil` specifies our HTML rendering functionality, `HtmlWriter` and `HtmlWriters` implement the functionality as a set of adapters, and the implicit argument to `htmlify` implicitly selects the correct adapter for any given argument. However, we can take things one step further to really simplify things.
134 |
--------------------------------------------------------------------------------
/src/pages/collections/for-comprehensions.md:
--------------------------------------------------------------------------------
1 | ## For Comprehensions
2 |
3 | We've discussed the main collection transformation functions---`map`, `flatMap`, `foldLeft`, `foldRight`, and `foreach`---and seen that they provide a powerful way of working with collections. They can become unwieldy to work with when dealing with many collections or many nested transformations. Fortunately Scala has special syntax for working with collections (in fact any class that implements `map` and `flatMap`) that makes complicated operations simpler to write. This syntax is known as a *for comprehension*.
4 |
5 |
6 | #### Not Your Father's For Loops {-}
7 |
8 | *for comprehensions* in Scala are very different to the C-style *for loops* in Java. There is no direct equivalent of either language's syntax in the other.
9 |
10 |
11 | Let's start with a simple example. Say we have the sequence `Seq(1, 2, 3)` and we wish to create a sequence with every element doubled. We know we can write
12 |
13 | ```tut:book
14 | Seq(1, 2, 3).map(_ * 2)
15 | ```
16 |
17 | The equivalent program written with a for comprehension is:
18 |
19 | ```tut:book
20 | for {
21 | x <- Seq(1, 2, 3)
22 | } yield x * 2
23 | ```
24 |
25 | We call the expression containing the `<-` a *generator*, with a *pattern* on the left hand side and a *generator expression* on the right. A for comprehension iterates over the elements in the generator, binding each element to the pattern and calling the `yield` expression. It combines the yielded results into a sequence of the same type as the original generator.
26 |
27 | In simple examples like this one we don't really see the power of for comprehensions---direct use of `map` and `flatMap` are often more compact in the simplest case. Let's try a more complicated example. Say we want to double all the numbers in `Seq(Seq(1), Seq(2, 3), Seq(4, 5, 6))` and return a flattened sequence of the results. To do this with `map` and `flatMap` we must nest calls:
28 |
29 | ```tut:book
30 | val data = Seq(Seq(1), Seq(2, 3), Seq(4, 5, 6))
31 |
32 | data.flatMap(_.map(_ * 2))
33 | ```
34 |
35 | This is getting complicated. The equivalent for comprehension is much more ... comprehensible.
36 |
37 | ```tut:book
38 | for {
39 | subseq <- data
40 | element <- subseq
41 | } yield element * 2
42 | ```
43 |
44 | This gives us an idea of what the for comprehensions does. A general for comprehension:
45 |
46 | ```tut:book:invisible
47 | val a: Seq[Int] = Seq.empty
48 | val b: Seq[Int] = Seq.empty
49 | val c: Seq[Int] = Seq.empty
50 | val e: Int = 0
51 | ```
52 |
53 | ```tut:book:silent
54 | for {
55 | x <- a
56 | y <- b
57 | z <- c
58 | } yield e
59 | ```
60 |
61 | translates to:
62 |
63 | ```tut:book:silent
64 | a.flatMap(x => b.flatMap(y => c.map(z => e)))
65 | ```
66 |
67 | The intuitive understanding of the code is to iterate through all of the sequences in the generators, mapping the `yield` expression over every element therein, and accumulating a result of the same type as sequence fed into the first generator.
68 |
69 | Note that if we omit the `yield` keyword before the final expression, the overall type of the `for` comprehension becomes `Unit`. This version of the `for` comprehension is executed purely for its side-effects, and any result is ignored. Revisiting the doubling example from earlier, we can print the results instead of returning them:
70 |
71 | ```tut:book:silent
72 | for {
73 | seq <- Seq(Seq(1), Seq(2, 3))
74 | elt <- seq
75 | } println(elt * 2) // Note: no 'yield' keyword
76 | // 2
77 | // 4
78 | // 6
79 | ```
80 |
81 | The equivalent method calls use `flatMap` as usual and `foreach` in place of the final `map`:
82 |
83 | ```scala
84 | a.flatMap(x => b.flatMap(y => c.foreach(z => e)))
85 | ```
86 |
87 | We can use parentheses instead of braces to delimit the generators in a for loop. However, we must use semicolons to separate the generators if we do. Thus:
88 |
89 | ```tut:book:silent
90 | for (
91 | x <- a;
92 | y <- b;
93 | z <- c
94 | ) yield e
95 | ```
96 |
97 | is equivalent to:
98 |
99 | ```tut:book:silent
100 | for {
101 | x <- a
102 | y <- b
103 | z <- c
104 | } yield e
105 | ```
106 |
107 | Some developers prefer to use parentheses when there is only one generator and braces otherwise:
108 |
109 | ```tut:book:silent
110 | for(x <- Seq(1, 2, 3)) yield {
111 | x * 2
112 | }
113 | ```
114 |
115 | We can also use braces to wrap the yield expression and convert it to a *block* as usual:
116 |
117 | ```scala
118 | for {
119 | // ...
120 | } yield {
121 | // ...
122 | }
123 | ```
124 |
125 | ### Exercises
126 |
127 | *(More) Heroes of the Silver Screen*
128 |
129 | Repeat the following exercises from the previous section *without using `map` or `flatMap`*:
130 |
131 | *Nolan Films*
132 |
133 | List the names of the films directed by Christopher Nolan.
134 |
135 |
136 | ```tut:book:invisible
137 | case class Film(name: String, imdbRating: Double)
138 | case class Director(name: String, films: Seq[Film])
139 | val nolan = Director("Christopher Nolan", Seq.empty)
140 | val directors: Seq[Director] = Seq(nolan)
141 | ```
142 |
143 | ```tut:book:silent
144 | for {
145 | film <- nolan.films
146 | } yield film.name
147 | ```
148 |
149 |
150 | *Cinephile*
151 |
152 | List the names of all films by all directors.
153 |
154 |
155 | ```tut:book:silent
156 | for {
157 | director <- directors
158 | film <- director.films
159 | } yield film.name
160 | ```
161 |
162 |
163 | *High Score Table*
164 |
165 | Find all films sorted by descending IMDB rating:
166 |
167 |
168 | This one's a little trickier. We have to calculate the complete list of films first before sorting them with `sortWith`. Precedence rules require us to wrap the whole `for / yield` expression in parentheses to achieve this in one expression:
169 |
170 | ```tut:book:silent
171 | (for {
172 | director <- directors
173 | film <- director.films
174 | } yield film).sortWith((a, b) => a.imdbRating > b.imdbRating)
175 | ```
176 |
177 | Many developers prefer to use a temporary variable to make this code tidier:
178 |
179 | ```tut:book:silent
180 | val films = for {
181 | director <- directors
182 | film <- director.films
183 | } yield film
184 |
185 | films sortWith { (a, b) =>
186 | a.imdbRating > b.imdbRating
187 | }
188 | ```
189 |
190 |
191 | *Tonight's Listings*
192 |
193 | Print the following for every film: `"Tonight only! FILM NAME by DIRECTOR!"`
194 |
195 |
196 | We can drop the `yield` keyword from the `for` expression to achieve `foreach`-like semantics:
197 |
198 | ```tut:book:silent
199 | for {
200 | director <- directors
201 | film <- director.films
202 | } println(s"Tonight! ${film.name} by ${director.name}!")
203 | ```
204 |
205 |
--------------------------------------------------------------------------------