@@ -52,6 +52,8 @@ class Counter extends ActionListener {
5252 - Handlers of events are also first-class
5353 - Complex handlers can be composed from primitive ones
5454** Recap: Functions and Pattern Matching
55+ - Recap: Case Classes
56+ Case classes are Scala's preferred way to define complex data.
5557- Representation of JSON in Scala
5658#+begin_src scala
5759abstract class JSON
@@ -62,7 +64,6 @@ case class JStr (str: String) extends JSON
6264case class JBool (b: Boolean) extends JSON
6365case object JNull extends JSON
6466#+end_src
65- #+NAME: Example
6667#+begin_src scala
6768val data = JObj(Map(
6869 "firstName" -> JStr("John"),
@@ -80,3 +81,94 @@ val data = JObj(Map(
8081 "type" -> JStr("fax"), "number" -> JStr("646 555-4567")
8182 )) )) ))
8283#+end_src scala
84+ - Pattern Matching
85+ Here's a method that returns the string representation JSON data:
86+ #+begin_src scala
87+ def show(json: JSON): String = json match {
88+ case JSeq(elems) =>
89+ "[" + (elems map show mkString ",") + "]"
90+ case JObj(bindings) =>
91+ val assocs = bindings map {
92+ case (key, value) => "\"" + key + "\": " + show(value)
93+ }
94+ "{" + (assocs mkString ", ") + "}"
95+ case JNum(num) => num.toString
96+ case JStr(str) => '\"' + str + '\"'
97+ case JBool(b) => b.toString
98+ case JNull => "null"
99+ }
100+ #+end_src scala
101+ - Functions Are Objects
102+ In Scala, every concrete type is the type of some class or trait.
103+
104+ The function type is no exception. A type like
105+
106+ src_scala{JBinding => String}
107+
108+ is just a shorthand for
109+
110+ src_scala{scala.Function1[JBinding, String]}
111+
112+ where =scala.Function1= is a trait and =JBinding= and =String= are its type arguments.
113+ - The Function1 Trait
114+ Here's an outline of that =Function1=:
115+ #+begin_src scala
116+ trait Function[-A, +R] {
117+ def apply(x: A): R
118+ }
119+ #+end_src
120+ The pattern matching block
121+ #+begin_src scala
122+ { case (key, value)=> key + ": " + value }
123+ #+end_src
124+ expands to the =Function1= instance
125+ #+begin_src scala
126+ new Function1[JBinding, String] {
127+ def apply(x: JBinding) = x match {
128+ case (key, value) => key + ": " + show(value)
129+ }
130+ }
131+ #+end_src
132+ - Subclassing Functions
133+ One nice aspect of functions being traits is that we can subclass the function type.
134+
135+ For instance, maps are functions from keys to values:
136+
137+ src_scala{trait Map[Key, Value] extends (Key => Value) ...}
138+
139+ Sequences are functions from =int= indices to values:
140+
141+ src_scala{trait Seq[Elem] extends Int => Elem}
142+
143+ That's why we can write
144+
145+ =elems(i)=
146+
147+ for sequence (and array) indexing.
148+ - Partial Functions
149+ #+begin_src scala
150+ val f: PartialFunction[String, String] = { case "ping" => "pong"}
151+ f.isDefinedAt("ping") // true
152+ f.isDefinedAt("pong") // false
153+ #+end_src
154+ The partial function trait is defined as follows:
155+ #+begin_src scala
156+ trait PartialFunction[-A, +R] extends Function1[-A, +R] {
157+ def apply(x: A): R
158+ def isDefinedAt(x: A): R
159+ }
160+ #+end_src
161+ - Partial Function Objects
162+ If the expected type is a =PartialFunction=, the Scala compiler willl expand src_scala{{ case "ping" => "pong" }}
163+
164+ as follows:
165+ #+begin_src scala
166+ new PartialFunction[String, String] {
167+ ...
168+ def isDefinedAt(x: String) = x match {
169+ case "ping" => true
170+ case _ => false
171+ }
172+ }
173+ #+end_src
174+ Note: =isDefinedAt= will only be determined by the outmost pattern
0 commit comments