cse 130: spring 2012 - cseweb.ucsd.educseweb.ucsd.edu/.../lec-scalacrash.markdown.pdf · scala 101:...

32
CSE 130: Spring 2012 Crash Course in Scala Ranjit Jhala, UC San Diego What is Scala ? “Java + ML + Extra Magic” Created by Martin Odersky @ EPFL Widely used (Twitter, FourSquare, LinkedIn, . . . ) Why Scala? Why Scala: Multi Paradigm Object-Functional Programming Post-Functional Programming Interesting blend, many exciting new features Why Scala: Bleeding Edge Modern type system (subclassing, generics, implicits, . . . ) Modern concurrency (actors, collections, . . . ) Seamless integration with Java Because I wanted to learn how it works! 1

Upload: others

Post on 22-May-2020

5 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: CSE 130: Spring 2012 - cseweb.ucsd.educseweb.ucsd.edu/.../lec-scalacrash.markdown.pdf · Scala 101: Read-Eval-Print Loop The easiest way to get started is with Scala’s REPL $ scala

CSE 130: Spring 2012

Crash Course in Scala

Ranjit Jhala, UC San Diego

What is Scala ?

• “Java + ML + Extra Magic”

• Created by Martin Odersky @ EPFL

• Widely used (Twitter, FourSquare, LinkedIn, . . . )

Why Scala?

Why Scala: Multi Paradigm

• Object-Functional Programming

• Post-Functional Programming

• Interesting blend, many exciting new features

Why Scala: Bleeding Edge

• Modern type system (subclassing, generics, implicits, . . . )

• Modern concurrency (actors, collections, . . . )

• Seamless integration with Java

• Because I wanted to learn how it works!

1

Page 2: CSE 130: Spring 2012 - cseweb.ucsd.educseweb.ucsd.edu/.../lec-scalacrash.markdown.pdf · Scala 101: Read-Eval-Print Loop The easiest way to get started is with Scala’s REPL $ scala

Plan: Next 6 lectures

Whirlwind Overview + Advanced Features

1. “Crash course”: Expressions, Values, Types

2. Classes, Subtyping & Generic Polymorphism

3. Inheritance, Traits and Mixins

4. Implicits and Type-Classes

5. Laziness

6. Concurrency: Actors, Map-Reduce

Many Resources

Online

• Martin Odersky’s First Steps in Scala

• Twitter’s Scala School

• Matt Might’s Scala In Small Bites

• API Search Engine scalex.org

Books

• Programming in Scala by Odersky, Spoon & Venners

• Scala for the Impatient by Horstmann

Lets Start the “Crash Course”!

Scala 101: Expressions & Types

Like ML, Scala is statically typed

• Almost everything is an expression, which has a type

• Type system is rather different than ML’s. . .

2

Page 3: CSE 130: Spring 2012 - cseweb.ucsd.educseweb.ucsd.edu/.../lec-scalacrash.markdown.pdf · Scala 101: Read-Eval-Print Loop The easiest way to get started is with Scala’s REPL $ scala

Scala 101: Read-Eval-Print Loop

The easiest way to get started is with Scala’s REPL

$ scala

Welcome to Scala version 2.9.0.1 OpenJDK...

Type in expressions to have them evaluated.

Type :help for more information.

scala>

Scala 101: Read-Eval-Print Loop

Enter expressions and have them evaluated

scala> 2

res0: Int = 2

scala> 2 + 3

res1: Int = 5

Everything is an “Object”

So when you type:

2 + 3

the compiler sees the method call:

2.+(3)

So + is just a method call! (as are many other things. . . )

Everything is an “Object”: Overloading

Furthermore, unlike ML (and like Java) Scala supports “overloading”

scala> 2 + "cat"

res3: String = 2cat

scala> 2 + 3.0

res4: Double = 5.0

Each of these calls the appropriate method on the receiver Int.

3

Page 4: CSE 130: Spring 2012 - cseweb.ucsd.educseweb.ucsd.edu/.../lec-scalacrash.markdown.pdf · Scala 101: Read-Eval-Print Loop The easiest way to get started is with Scala’s REPL $ scala

Everything is an “Object”: Overloading

But don’t get carried away. . .

scala> 2 + true

<console>:8: error: overloaded method value + with alternatives:

(x: Double)Double <and>

(x: Float)Float <and>

(x: Long)Long <and>

(x: Int)Int <and>

(x: Char)Int <and>

(x: Short)Int <and>

(x: Byte)Int <and>

(x: String)String

cannot be applied to (Boolean)

2 + true

^

Fair enough.

Basic Data

You have your basic built-in types. . .

scala> 4.2 * 6.7

res8: Double = 28.14

scala> true || falseres9: Boolean = true

scala> ’c’

res10: Char = c

Basic Data

Strings are borrowed from Java. . .

scala> "cat"

res25: java.lang.String = cat

scala> "cat" + "dog"

res26: java.lang.String = catdog

4

Page 5: CSE 130: Spring 2012 - cseweb.ucsd.educseweb.ucsd.edu/.../lec-scalacrash.markdown.pdf · Scala 101: Read-Eval-Print Loop The easiest way to get started is with Scala’s REPL $ scala

scala> "cat" * 3

res26: java.lang.String = catcatcat

Basic Data

. . . and you can take whatever you like from Java

scala> import java.util.Date

import java.util.Date

scala> new Date()

res27: java.util.Date = Wed May 09 11:17:29 PDT 2012

So every Java library in the known universe trivially usable in Scala.

Variables

Two ways to introduce variables

• Immutable (a.k.a. The “right” way)

• Mutable (a.k.a. The “if-you-must” way)

Immutable Variables

• With the val keyword

scala> val x = 2

x: Int = 2

• val x = e is like Ocaml’s let x = e

• But don’t try to change (re-assign) such a variable!

scala> x = x + 1

<console>:8: error: reassignment to val

x = x + 1

^

• Snap.

5

Page 6: CSE 130: Spring 2012 - cseweb.ucsd.educseweb.ucsd.edu/.../lec-scalacrash.markdown.pdf · Scala 101: Read-Eval-Print Loop The easiest way to get started is with Scala’s REPL $ scala

. . . and if you absolutely must: Immutable Variables

scala> var z = 1

z: Int = 1

scala> z += 1

scala> z

res1: Int = 2

scala> z = 3

z: Int = 3

We will revisit val and var when we talk about objects and fields.

Compound Data: Tuples

Scala comes equipped with modern ameneties like tuples

scala> val t = ("cat", 12)

t: (java.lang.String, Int) = (cat,12)

scala> val t2 = ("mickey", 12, "mouse")

t2: (java.lang.String, Int, java.lang.String)

= (mickey,12,mouse)

scala> val t3 = ("mickey", (12, "mouse"))

t3: (java.lang.String, (Int, java.lang.String))

= (mickey,(12,mouse))

the type is written (T1, T2) or (T1, T2, T3)

Compound Data: Tuples

To access the tuple elements, you can use pattern matching

scala> t

res7: (java.lang.String, Int) = (cat,12)

scala> val (p, q) = t

p: java.lang.String = cat

q: Int = 12

6

Page 7: CSE 130: Spring 2012 - cseweb.ucsd.educseweb.ucsd.edu/.../lec-scalacrash.markdown.pdf · Scala 101: Read-Eval-Print Loop The easiest way to get started is with Scala’s REPL $ scala

or the tuple field accessors . 1 or . 2 etc.

scala> t._1

res5: java.lang.String = cat

scala> t._2

res6: Int = 12

Compound Expressions

You can sequence expressions to get bigger expressions

scala> :paste

// Entering paste mode (ctrl-D to finish)

{ println("hello world")

2 + 8 }

// Exiting paste mode, now interpreting.

hello world

res0: Int = 10

Paste-mode lets you enter multi-line expressions in REPL

Functions

Many ways to define functions

Functions

Many ways to define functions

def inc(x: Int): Int = {x + 1

}

Call a function in the usual way

scala> inc(4)

res3: Int = 5

7

Page 8: CSE 130: Spring 2012 - cseweb.ucsd.educseweb.ucsd.edu/.../lec-scalacrash.markdown.pdf · Scala 101: Read-Eval-Print Loop The easiest way to get started is with Scala’s REPL $ scala

Functions

No need for explicit return

def adder(x: Int, y: Int): Int = {println("adder(x=%d, y=%d)".format(x, y))

x + y

}

Block evaluates to last expression

scala> adder(2, 3)

adder(x=2, y=3)

res1: Int = 5

Curried Functions

def curriedAdder(x: Int)(y: Int): Int = {println("You called curried adder: %d %d". format(x, y))

x + y

}

which is called thus

scala> curriedAdder(2)(3)

You called curried adder: 2 3

res0: Int = 5

Functions with no name

A.k.a anonymous functions

Like Ocaml’s fun x -> e

scala> (x: Int) => x + 1

res3: (Int) => Int = <function1>

scala> (x: Int, y: Int) => x + y

res2: (Int, Int) => Int = <function2>

Note the types of the functions

8

Page 9: CSE 130: Spring 2012 - cseweb.ucsd.educseweb.ucsd.edu/.../lec-scalacrash.markdown.pdf · Scala 101: Read-Eval-Print Loop The easiest way to get started is with Scala’s REPL $ scala

Functions with no name

Call by placing argument in front

scala> ((x: Int) => x + 1)(8)

res3: Int = 9

Makes sense to bind to a name first

scala> val inc = (x: Int) => x + 1

inc: (Int) => Int = <function1>

scala> inc(5)

res5: Int = 6

Functions are Objects Too!

Functions are Objects Too!

Functions are just objects with apply method

scala> object inc { def apply(x: Int) = x + 1 }

Call them like so

scala> inc(5)

res: Int = 6

Functions are Objects Too!

Functions are just objects with apply method

When you write f(args) Scala reads f.apply(args)

• Enables many fun features

• “Uniform Access Principle” . . .

9

Page 10: CSE 130: Spring 2012 - cseweb.ucsd.educseweb.ucsd.edu/.../lec-scalacrash.markdown.pdf · Scala 101: Read-Eval-Print Loop The easiest way to get started is with Scala’s REPL $ scala

Functions are Objects Too!

Anything with apply can be called

scala> val str = "megalomaniac"

str: String = megalomaniac

scala> str(2)

res: Char = g

So far: Basic Data, Variables, Functions

Next: Control Expressions

Control Expressions

The usual suspects . . .

• if-else

• try-catch

• while-loops

• for-loops

Control Expressions: If-Else

Put the then and else expressions inside {...}

def fac(n: Int) = {if (n > 0) {n * fac(n-1)

} else {1

}}

10

Page 11: CSE 130: Spring 2012 - cseweb.ucsd.educseweb.ucsd.edu/.../lec-scalacrash.markdown.pdf · Scala 101: Read-Eval-Print Loop The easiest way to get started is with Scala’s REPL $ scala

Control Expressions: Pattern Matching (FTW!)

Scala has pattern matching too . . .

def fac(n: Int): Int =

n match {case n if (n > 0) => n * fac(n-1)

case _ => 1

}

. . . more on this later.

Digression: About Those Types. . .

(Unlike ML), you have to write down some types in Scala.

Function arguments and returns

scala> def fac(n: Int) =

| n match {| case n if (n > 0) => n * fac(n-1)

| case _ => 1

| }<console>:10: error: recursive method fac needs result type

case n if (n > 0) => n * fac(n-1)

Scala’s Local Type Inference figures out the rest!

Control Expressions: Try-Catch

Put the body expression inside {...}

import java.io.File

def fileContents(file: String): List[String] = {val f = new java.io.File(file)

try {scala.io.Source.fromFile(f).getLines().toList

} catch {

case e: java.io.FileNotFoundException => {println("WTF! No such file exists")

List()

11

Page 12: CSE 130: Spring 2012 - cseweb.ucsd.educseweb.ucsd.edu/.../lec-scalacrash.markdown.pdf · Scala 101: Read-Eval-Print Loop The easiest way to get started is with Scala’s REPL $ scala

}}

}

Control Expressions: Try-Catch (contd.)

You can run it thus:

scala> val lines = fileContents("lec1-scala-intro.markdown")

lines: List[String] = List(% CSE 130: Spring 2012, ...)

and if you call it with a junk file:

scala> val lines = fileContents("foobar")

WTF! No such file exists

lines: List[String] = List()

Control Expressions: While-loop

Old-school while loops . . .

def fac(n: Int) = {var res = 1

var count = n

while (count > 0) {res *= count

count -= 1

}res

}

Control Expressions: For-loop

. . . and of course, for-loops too. . .

scala> for (i <- 1 to 5) println(i)

1

2

3

4

5

12

Page 13: CSE 130: Spring 2012 - cseweb.ucsd.educseweb.ucsd.edu/.../lec-scalacrash.markdown.pdf · Scala 101: Read-Eval-Print Loop The easiest way to get started is with Scala’s REPL $ scala

Control Expressions: For-loop

Or if you want a step. . .

scala> for (i <- 1 to 5 by 2) println(i)

1

3

5

Control Expressions: For-loop

Or count in the other direction . . .

scala> for (i <- 5 to 1 by -1) println(i)

5

4

3

2

1

Control Expressions: For-loop

Actually, for-loops are quite special . . .

scala> for (i <- "special") println(i)

s

p

e

c

i

a

l

Hmm. Whats going on?

Scala Batteries Included: Collections

Batteries Included: Collections

Scala bundled with with a rich set of Collections

13

Page 14: CSE 130: Spring 2012 - cseweb.ucsd.educseweb.ucsd.edu/.../lec-scalacrash.markdown.pdf · Scala 101: Read-Eval-Print Loop The easiest way to get started is with Scala’s REPL $ scala

• Arrays

• Lists

• (Hash) Sets

• (Hash) Maps

• Streams . . .

These are immutable OR mutable

Batteries Included: Arrays

(Mutable) Arrays

scala> val a = Array("cow", "dog", "mouse")

res14: Array[java.lang.String] = Array(cow, dog, mouse)

Note the type: Array[String].

Arrays have a fixed length

scala> a.length

res15: Int = 3

Batteries Included: Arrays

(Mutable) Arrays can be randomly accessed

scala> a(2)

res16: java.lang.String = mouse

• “Uniform access principle”

• a(2) read as lookup method call a.apply(2)

14

Page 15: CSE 130: Spring 2012 - cseweb.ucsd.educseweb.ucsd.edu/.../lec-scalacrash.markdown.pdf · Scala 101: Read-Eval-Print Loop The easiest way to get started is with Scala’s REPL $ scala

Batteries Included: Arrays

(Mutable) Arrays can be randomly updated

scala> a(0) = "capuchin"

scala> a

res19: Array[java.lang.String] = Array(capuchin, dog, mouse)

• “Uniform access principle”

• a(0) = "capuchin" read as update method call a.update(0,"capuchin")

Batteries Included: For-Loops

(Mutable) Arrays can also be looped over. . .

scala> for (animal <- a) println(animal)

capuchin

dog

mouse

Loathsome “off-by-one” errors BEGONE!

But immutable better if you can help it. . .

Batteries Included: Lists

Batteries Included: Lists

(Immutable) Lists

scala> val xs = List(1,2,3,4)

xs: List[Int] = List(1, 2, 3, 4)

scala> val ys = List("cat", "dog", "moose", "gorilla")

ys: List[java.lang.String] = List(cat, dog, moose, gorilla)

Cannot change a list!!

15

Page 16: CSE 130: Spring 2012 - cseweb.ucsd.educseweb.ucsd.edu/.../lec-scalacrash.markdown.pdf · Scala 101: Read-Eval-Print Loop The easiest way to get started is with Scala’s REPL $ scala

scala> ys(0) = "kite"

<console>:9: error: value update is not a member of List[java.lang.String]

ys(0) = "kite"

^

Batteries Included

Quite a bit like ML lists. . .

scala> val zs = "chicken" :: ys

zs: List[java.lang.String] = List(chicken, cat, dog, moose, gorilla)

can be accessed via patterns

def listConcat(xs: List[String]): Int =

xs match {case Nil => ""

case h::t => h + listConcat(t)

}

Which you can call like so:

scala> listConcat(zs)

res10: chickencatdogmoosegorilla

Batteries Included

(Immutable) Lists

You can also append them

scala> List(1,2,3) ++ List(4,5,6)

res11: List[Int] = List(1,2,3,4,5,6)

and, loop over them too . . .

scala> for (animal <- zs) println(animal)

chicken

cat

dog

moose

gorilla

16

Page 17: CSE 130: Spring 2012 - cseweb.ucsd.educseweb.ucsd.edu/.../lec-scalacrash.markdown.pdf · Scala 101: Read-Eval-Print Loop The easiest way to get started is with Scala’s REPL $ scala

Batteries Included: Hash-Maps

Batteries Included: Hash-Maps

Key-Value Maps, that can be immutable (by default)

scala> val numNames = Map("one" -> 1, "two" -> 2, "three" -> 3)

numNames: scala.collection.immutable.Map[java.lang.String,Int]

= Map(one -> 1, two -> 2, three -> 3)

Batteries Included: Hash-Map Lookup

Key-Value Maps, that can be immutable (by default)

You can lookup the value of a key much like arrays

scala> numNames("three")

res12: Int = 3

Batteries Included: Hash-Maps Lookup

Key-Value Maps, that can be immutable (by default)

If the value doesn’t exist though. . . Exception

scala> numNames("nine")

java.util.NoSuchElementException: key not found: nine

.

.

.

Batteries Included: Hash-Maps Membership

Key-Value Maps, that can be immutable (by default)

Moral, look before you leap

scala> numNames.contains("nine")

res13: Boolean = false

or using the cleaner notation

scala> numNames contains "nine"

res14: Boolean = false

17

Page 18: CSE 130: Spring 2012 - cseweb.ucsd.educseweb.ucsd.edu/.../lec-scalacrash.markdown.pdf · Scala 101: Read-Eval-Print Loop The easiest way to get started is with Scala’s REPL $ scala

Batteries Included: Hash-Maps Adding Keys

Key-Value Maps, that can be immutable (by default)

Would be nice to extend a map with new key-value bindings.

How do you think its done?

Batteries Included: Hash-Maps Adding Keys

Key-Value Maps, that can be immutable (by default)

Would be nice to extend a map with new key-value bindings. . .

scala> numNames + ("nine" -> 9)

res15: scala.collection.immutable.Map[java.lang.String,Int]

= Map(one -> 1, two -> 2, three -> 3, nine -> 9)

Note the above is a brand new map . . .

scala> numNames contains "nine"

res16: Boolean = false

Batteries Included: Hash-Maps Adding Keys

Key-Value Maps, that can be immutable (by default)

Would be nice to extend a map with new key-value bindings . . .

scala> val newMap = numNames + ("nine" -> 9)

newMap: scala.collection.immutable.Map[java.lang.String,Int]

= Map(one -> 1, two -> 2, three -> 3, nine -> 9)

. . . Bind the result to a new map.

scala> newMap("nine")

res17: Int = 9

Batteries Included: Mutable Hash-Maps (!)

Batteries Included: Mutable Hash-Maps

(pssst.) There are mutable Key-Value Maps too. . .

18

Page 19: CSE 130: Spring 2012 - cseweb.ucsd.educseweb.ucsd.edu/.../lec-scalacrash.markdown.pdf · Scala 101: Read-Eval-Print Loop The easiest way to get started is with Scala’s REPL $ scala

scala> import scala.collection.mutable.HashMap

scala> val mmap : HashMap[String, Int] = HashMap()

scala> mmap += "mon" -> 1

scala> mmap += "tue" -> 2

scala> mmap += "wed" -> 3

scala> mmap("tue")

res18: Int = 2

Note: type parameters for the key (String) and value (Int)

Recap: Expressions, Variables, Functions, Col-lections

QUIZ: What is the value of res?

import scala.collection.mutable.HashMap

val mutMap: HashMap[String, Int] = HashMap()

mutMap += "mon" -> 1

mutMap += "mon" -> 2

val res = mutMap("mon")

A. No value, Type Error (cannot update val)

B. No value, Runtime Exception (key not found)

C. 1: Int

D. 2: Int

E. None: Option[Int]

QUIZ: What is the value of res?

import scala.collection.mutable.HashMap

var immutMap : Map[String, Int] = Map()

immutMap += "mon" -> 1

immutMap += "mon" -> 2

val res = immutMap("mon")

A. No value, Type Error

B. No value, Runtime Exception (NotFound)

19

Page 20: CSE 130: Spring 2012 - cseweb.ucsd.educseweb.ucsd.edu/.../lec-scalacrash.markdown.pdf · Scala 101: Read-Eval-Print Loop The easiest way to get started is with Scala’s REPL $ scala

C. 1: Int

D. 2: Int

E. None: Option[Int]

QUIZ: What is the value of res?

import scala.collection.immutable.Map

var immutMap : Map[String, Int] = Map()

var other = immutMap

immutMap += "mon" -> 1

immutMap += "mon" -> 2

val res = other("mon")

A. No value, Type Error

B. No value, Runtime Exception (NotFound)

C. 1: Int

D. 2: Int

E. None: Option[Int]

QUIZ: What is the value of res?

˜˜˜{.scala} import scala.collection.mutable.HashMap var immutMap :Map[String, Int] = Map() var other = immutMap immutMap += “mon” -> 1immutMap += “mon” -> 2 val res = other(“mon”)

A. No value, Type Error

B. No value, Runtime Exception (NotFound)

C. 1: Int

D. 2: Int

E. None: Option[Int]

How to operate on collections?

How to operate on collections? HOFS!

Collections and Higher-Order Functions

All collection objects equipped with HOFs

20

Page 21: CSE 130: Spring 2012 - cseweb.ucsd.educseweb.ucsd.edu/.../lec-scalacrash.markdown.pdf · Scala 101: Read-Eval-Print Loop The easiest way to get started is with Scala’s REPL $ scala

• filter

• map

• foreach

• foldLeft, foldRight

• and many others!

HOFS + Collections: filter

All collection objects equipped with HOFs!

scala> "MaSsIvEaTtAcK".filter(c => c.isUpper)

res19: String = MSIETAK

Or, with equivalent, simpler syntax for HOFS

scala> "MaSsIvEaTtAcK".filter(_.isUpper)

res20: String = MSIETAK

HOFS + Collections: filter

All collection objects equipped with HOFs!

scala> List(1,2,3,4,5,6,7,8).filter(_ % 2 == 0)

res21: List[Int] = List(2,4,6,8)

scala> Array(1,2,3,4,5,6,7,8).filter(_ % 2 == 0)

res21: Array[Int] = Array(2,4,6,8)

HOFS + Collections: filter

With Map, the filter is over a tuple

scala> numNames.filter(_._1.length = 3)

res24: scala.collection.immutable.Map[java.lang.String,Int]

= Map(one -> 1, two -> 2)

21

Page 22: CSE 130: Spring 2012 - cseweb.ucsd.educseweb.ucsd.edu/.../lec-scalacrash.markdown.pdf · Scala 101: Read-Eval-Print Loop The easiest way to get started is with Scala’s REPL $ scala

HOFS + Collections: filter

With Map, the filter is over a tuple

You can use anonymous functions over tuples

scala> numNames.filter({case (k, v) => k.length = 3})res23: scala.collection.immutable.Map[java.lang.String,Int]

= Map(one -> 1, two -> 2)

HOFS + Collections: map

All collection objects equipped with HOFs!

scala> "MaSsIvEaTtAcK".map(_.toUpper)

res24: String = MASSIVEATTACK

scala> List(1,2,3).map(_ * 100)

res25: List[Int] = List(100, 200, 300)

scala> Array("cat", "dog", "wabbit").map(_.map(_.toUpper))

res26: Array[String] = Array(CAT, DOG, WABBIT)

HOFS + Collections: foreach

foreach is like map but does an action, returns ()

scala> Array("cat", "dog", "wabbit").foreach(println(_))

cat

dog

wabbit

. . . so whats a for-loop?

HOFS + Collections: for-loops Revisited

for-loop is just a HOF!

for (a <- thing) { body }

is just same as

thing.foreach(a => body)

22

Page 23: CSE 130: Spring 2012 - cseweb.ucsd.educseweb.ucsd.edu/.../lec-scalacrash.markdown.pdf · Scala 101: Read-Eval-Print Loop The easiest way to get started is with Scala’s REPL $ scala

HOFS + Collections: for-loops Revisited

So you can loop over all collections

scala> numNames.foreach({case (k, v) => println(k + " ~~~~~> " + v)})one ~~~~~> 1

two ~~~~~> 2

three ~~~~~> 3

or if you prefer

scala> for ((k, v) <- numNames) { println(k + " ~~~~~> " + v) }one ~~~~~> 1

two ~~~~~> 2

three ~~~~~> 3

HOFS + Collections: for-loops Revisited

Another example:

scala> val dir = new java.io.File(".")

dir: java.io.File = .

scala> for (f <- dir.listFiles) println(f)

./slides.markdown

./scratch.markdown

./Monoid.scala

./Freq.scala

.

.

.

HOFS + Collections: for-loops Revisited

Sometimes, want to loop over some elements and skip others.

For example, to print names of all .scala files:

scala> for (f <- dir.listFiles

if f.getName.endsWith(".scala")) { println(f) }./Monoid.scala

./Freq.scala

23

Page 24: CSE 130: Spring 2012 - cseweb.ucsd.educseweb.ucsd.edu/.../lec-scalacrash.markdown.pdf · Scala 101: Read-Eval-Print Loop The easiest way to get started is with Scala’s REPL $ scala

QUIZ: HOFS + Collections: for-loops Revisited

Sometimes, want to loop over some elements and skip others.

for (x <- coll if cond) { body }

Is really a nice way of writing

A. coll.filter(x => body)

B. coll.filter(x => cond).foreach(x => body)

C. coll.foreach(x => body)

D. coll.foreach(x => body).filter(x => body)

HOFS + Collections: for-loops Revisited

More often, want to compute a collection as a value . . .

Suppose we have an Array of Strings . . .

val words = Array("you", "are", "doing", "it", "wrong")

. . . to turn it into a rant

scala> val rant = for (w <- words) yield w.toUpperCase

rant: Array[java.lang.String] = List(YOU, ARE, DOING, IT, WRONG)

. . . Note the output is also an Array.

HOFS + Collections: for-loops Revisited

More often, want to compute a collection as a value . . .

Works for any collection. . .

scala> for (w <- fileContents("lec-scalacrash.markdown")

yield w.toUpperCase

res: List[String] = List(% CSE 130: SPRING 2012, ...)

24

Page 25: CSE 130: Spring 2012 - cseweb.ucsd.educseweb.ucsd.edu/.../lec-scalacrash.markdown.pdf · Scala 101: Read-Eval-Print Loop The easiest way to get started is with Scala’s REPL $ scala

QUIZ: HOFS + Collections: for-loops Revisited

More often, want to compute a collection as a value . . .

for (x <- coll) yield expr

Is really a nice way of writing

A. coll.foreach(x => expr)

B. coll.filter(x => expr)

C. coll.map(x => body)

HOFS + Collections: for-loops Revisited

More often, want to compute a collection as a value . . .

. . . after some processing.

E.g., to find all .scala files in a directory

scala> val scalaFiles = for (f <- dir.listFiles

if f.getName.endsWith(".scala"))

yield f

scalaFiles: Array[java.io.File] = Array(./Monoid.scala, ./Freq.scala)

HOFS + Collections: for-loops Revisited

Sometimes, want to return a collection. . .

. . . after some processing.

scala> import scala.io.Source._

scala> val fileSizes = for (f <- dir.listFiles

if f.getName.endsWith(".scala"))

yield fromFile(f).length

fileSizes: Array[Int] = Array(349, 406)

25

Page 26: CSE 130: Spring 2012 - cseweb.ucsd.educseweb.ucsd.edu/.../lec-scalacrash.markdown.pdf · Scala 101: Read-Eval-Print Loop The easiest way to get started is with Scala’s REPL $ scala

HOFS + Collections: for-loops Revisited

Sometimes, want to return a collection. . .

. . . after some processing.

for (x <- coll if cond) yield expr

Is really another way of writing

coll.filter(x => cond).map(x => expr)

HOFS + Collections: Nested for-loops

You can nest for-loops too:

scala> for (i <- 1 to 3; j <- 1 to 3) {println ("%d and %d" format(i, j))

}1 and 1

1 and 2

1 and 3

2 and 1

2 and 2

2 and 3

3 and 1

3 and 2

3 and 3

HOFS + Collections: Nested for-loops

You can nest for-loops too,

and then return a collection as the result:

scala> for (i <- 1 to 3; j <- 1 to 3) yield (i, j)

res: scala.collection.immutable.IndexedSeq[(Int, Int)]

= Vector((1,1), (1,2), (1,3), (2,1), (2,2), (2,3), (3,1), (3,2), (3,3))

26

Page 27: CSE 130: Spring 2012 - cseweb.ucsd.educseweb.ucsd.edu/.../lec-scalacrash.markdown.pdf · Scala 101: Read-Eval-Print Loop The easiest way to get started is with Scala’s REPL $ scala

HOFS + Collections: Nested for-loops

You can nest for-loops too, what does this return

and then return a collection as the result

after filtering

scala> val res = for (i <- 1 to 3; j <- 1 to 3 if i < j)

yield (i, j)

res26: scala.collection.immutable.IndexedSeq[(Int, Int)]

= Vector((1,2), (1,3), (2,3))

HOFS + Collections: Nested for-loops

You can nest for-loops too, what does this return

and then return a collection as the result

after filtering

Again: this holds for any collection:

scala> val res = for (i <- List(1,2,3);

j <- List(4,5,6)

if i + j == 7)

yield (i, j)

res: List[(Int, Int)] = List((1,6), (2,5), (3,4))

HOFS + Collections: Nested for-loops

You can nest for-loops too, what does this return

and then return a collection as the result

val res = for (i <- List(1,2,3);

j <- List(4,5,6)

if i + j == 7)

yield (i, j)

So far, inner loop independent of outer but. . .

QUIZ: HOFS + Collections: Nested for-loops

Of course, you can nest for-loops too:

27

Page 28: CSE 130: Spring 2012 - cseweb.ucsd.educseweb.ucsd.edu/.../lec-scalacrash.markdown.pdf · Scala 101: Read-Eval-Print Loop The easiest way to get started is with Scala’s REPL $ scala

scala> val ll = List(List(1,2), List(3,4))

scala> val res = for (xs <- ll;

x <- xs)

yield x

What is the value of res?

A. List(1, 3)

B. List(List(1,2), List(3,4))

C. List((1,3), (1,4), (2,3), (2,4))

D. List(1,2,3,4)

E. List()

HOFS + Collections: Nested for-loops

Of course, you can nest for-loops too:

another example (wink wink) . . .

scala> for (w <- List("cat", "dog", "mouse"); c <- w) yield c

res: List[Char] = List(c, a, t, d, o, g, m, o, u, s, e)

. . . Note the output type is also List

Like the top-level sequence!

HOFS + Collections: Nested for-loops

Of course, you can nest for-loops too:

yet another example (wink wink) . . .

scala> for (w <- Array("cat", "dog", "mouse"); c <- w) yield c

res: Array[Char] = Array(c, a, t, d, o, g, m, o, u, s, e)

. . . Note the output type is also Array

28

Page 29: CSE 130: Spring 2012 - cseweb.ucsd.educseweb.ucsd.edu/.../lec-scalacrash.markdown.pdf · Scala 101: Read-Eval-Print Loop The easiest way to get started is with Scala’s REPL $ scala

QUIZ: HOFS + Collections: Nested for-loops

Of course, you can nest for-loops too:

val res = for (xs <- Iterator("cat", "dog", "mouse")

x <- xs)

yield x

What is the type of res?

A. String

B. List(String)

C. Iterator(String)

D. List(Char)

E. Iterator(Char)

HOFS + Collections: for-loops Revisited

Wait a minute! Remember this?

scala> for (i <- 1 to 5) println(i)

1

2

3

4

5

How does it work ?

HOFS + Collections: for-loops Revisited

Wait a minute! Remember this?

1 to 5 is a method call 1.to(5)

scala> 1 to 5

res: scala.collection.immutable.Range.Inclusive = Range(1, 2, 3, 4, 5)

29

Page 30: CSE 130: Spring 2012 - cseweb.ucsd.educseweb.ucsd.edu/.../lec-scalacrash.markdown.pdf · Scala 101: Read-Eval-Print Loop The easiest way to get started is with Scala’s REPL $ scala

HOFS + Collections: for-loops Revisited

If you want a step

scala> 1 to 10 by 2 // 1.to(10).by(2)

res3: scala.collection.immutable.Range = Range(1, 3, 5, 7, 9)

scala> 10 to 1 by -1 // 10.to(1).by(-1)

res4: scala.collection.immutable.Range = Range(10, 9, 8, 7, 6, 5, 4, 3, 2, 1)

scala> 10 to 1 by -2 // 10.to(1).by(-1)

res5: scala.collection.immutable.Range = Range(10, 8, 6, 4, 2)

You can do a LOT with collections!

So what does this do?

List(1,2,3,4,5).foldLeft(0)((x1, x2) => x1 + x2)

You can do a LOT with collections!

So what does this do?

List(1,2,3,4,5).foldLeft(0)(_ + _)

Here, ( + ) is a short hand for

(x1, x2) => arg1 + arg2

Btw, you can do a LOT with collections!

And, what does this do?

def foo(n: Int, k: Int) =

(1 to k).map(_ => n).foldLeft(1)(_ * _)

30

Page 31: CSE 130: Spring 2012 - cseweb.ucsd.educseweb.ucsd.edu/.../lec-scalacrash.markdown.pdf · Scala 101: Read-Eval-Print Loop The easiest way to get started is with Scala’s REPL $ scala

Put things together: Frequencies

Lets write a Frequency Finder

How often does a Char appear in a String

def freq(str: String): HashMap[Char, Int] = {val freqMap = new HashMap[Char, Int]

for (c <- str) {freqMap(c) = 1 + freqMap.getOrElse(c, 0)

// if(freqMap contains c){freqMap(c)}// else { 0 }

}freqMap

}

Lets write a Polymorphic Frequency Finder

Lets generalize a bit. (Make it polymorphic)

def freq[A](xs: Iterable[A]): HashMap[A, Int] = {val freqMap = new HashMap[A, Int]

for (x <- xs) {freqMap(x) = 1 + freqMap.getOrElse(x, 0)

}freqMap

}

Iterable[A] describes objects that can be iterated over. . .

Lets write a Polymorphic Frequency Finder

Can run it on Strings

scala> freq("caterpillar")

res: scala.collection.mutable.HashMap[Char,Int]

= Map(c -> 1, a -> 2, e -> 1, i -> 1, r -> 2, t -> 1, l -> 2, p -> 1)

or List

scala> freq(List(1,2,1,13,1,2,1,3,31,12,1))

res: scala.collection.mutable.HashMap[Int,Int]

= Map(12 -> 1, 3 -> 1, 13 -> 1, 1 -> 5, 2 -> 2, 31 -> 1)

or . . .

31

Page 32: CSE 130: Spring 2012 - cseweb.ucsd.educseweb.ucsd.edu/.../lec-scalacrash.markdown.pdf · Scala 101: Read-Eval-Print Loop The easiest way to get started is with Scala’s REPL $ scala

Compiling and Running

Compiling and Running

To make an executable, put the functions in a file e.g. foo.scala

object Freq { ... }

compile with

$ scalac foo.scala

and run with

$ scala FreqShow "lec1-scala-intro.markdown"

...

Compiling and Running

Or now run in the REPL

scala> val m = Freq("caterpillar")

scala> Freq.show(m, 1)

c : #

a : ##

e : #

i : #

r : ##

t : #

l : ##

p : #

Next Time: Types, Classes, Objects, Generics.

32