on the rest of the program [can] be described only in terms of its return type, and...the impact of the rest of the program on the function be described only in terms of its arguments”. (Victor Nicollet)
be changed. If you need to change an object, make your own copy. a quick detour back to Java... concurrency rollback of data simplicity String s1 = "san dimas high school football rules" String s2 = s1.toUpperCase println("string 1: " + s1); println("string 2: " + s2); powerful tough to mess with
string" val listOfThem: List[String] = List("yarn","twine","thread") val freshNewLongSkinnyThing: String = spinFromFiber("wool") tieInAKnot(longSkinnyThing) class Rope(type:String) { override def toString(): String = "You've put me on a diet!"; } val longSkinnyThing: Rope = new Rope("nautical") val listOfThem: List[String] = List(longSkinnyThing, new Rope("climbing"), new Rope("clothesline"), new Rope("jump")) val freshNewLongSkinnyThing: Rope = spinFromFiber("hemp") tieInAKnot(longSkinnyThing)
=> return type val addSpam: (String) => String = { (x:String) => x + " and Spam" } addSpam("Egg and Bacon") //result: "Egg and Bacon and Spam" val menuOptions = List(addSpam, withoutSpam) menuOptions(1)("Egg and Bacon and Spam") //result: "You can't have that"
= { new Fruit("apple"), new Fruit("cherry"), new Fruit("strawberry") }; for (int i = 0; i < fruits.length; i++) { System.out.println("Hey the other day I ate a " + fruits[i]; } } def talkAboutFruit = { val fruits = List(new Fruit("apple"), new Fruit("cherry"), new Fruit("strawberry")) for (i <- 0 until fruits.length) { System.out.println("Hey the other day I ate a " + fruits(i); } }
a function (list of parameters' types) => return type foreach(fruitList:List(fruits), theFunction: (Fruit) => Unit): Unit def foreach(fruitList:List(fruits), theFunction: (Fruit) => Unit ) = { for (i <- 0 until fruitList.length) { theFunction(fruits(i)) } } def talkAboutFruit = { val fruits = List(new Fruit("apple"), new Fruit("cherry"), new Fruit("strawberry")) val tellEm = { (f:Fruit) => System.out.println( "Hey the other day I ate a " + f) } foreach(fruits, tellEm) } }
Collection[A] { ... def foreach(theFunction: (A) => Unit): Unit ... } def talkAboutFruit = { val fruits = List(new Fruit("apple"), new Fruit("cherry"), new Fruit("strawberry")) val tellEm = { (f:Fruit) => System.out.println( "Hey the other day I ate a " + f) } fruits.foreach(tellEm) } }
can map(theFunction: (A) => B): Collection[B] def makePies: List[Pie] = { val fruits = List(new Fruit("apple"), new Fruit("cherry"), new Fruit("strawberry")) var pies = List() for (i <- 0 until fruits.length) { new Pie(fruits(i)) :: pies } pies } def makePies: List[Pie] = { val fruits = List(new Fruit("apple"), new Fruit("cherry"), new Fruit("strawberry")) val makePie = { (f: Fruit) => new Pie(f) } fruits.map(makePie) }
IceCream]) { for { p <- pies i <- iceCreams val serving = new Serving(p,i) if (serving.isGood) } yield { serving } } def pleaseEverybody(audience: List[Person], pies: List[Pie], ice Creams: List[IceCream]): List(ThankYou) { for { person <- audience p <- pies i <- iceCreams val serving = new Serving(p,i) if (serving.isGood) } yield { person.feed(serving) } }
type T inside, or None representing nothing. val someOption: Option[String] = Some("this is a value") val noneOption: Option[String] = None val theSomeValue = someOption.get //returns "this is a value" val someIsDefined = someOption.isDefined //returns true val theNoneValue = noneOption.get //throws NoSuchElementException val someIsDefined = someOption.isDefined //returns false
monad. The first thing is that I can wrap up a value inside of a new Thing...We have a function of type A => Thing; a function which takes some value and wraps it up inside a new Thing. We also have this fancy bind function, which digs inside our Thing and allows a function which we supply to use that value to create a new Thing. Scala calls this function “flatMap“.... What’s interesting here is the fact that bind is how you combine two things together in sequence. We start with one thing and use its value to compute a new thing." —Daniel Spiewak
abstracts away a for-loop, letting us create a new List from an existing list. For Options, it abstracts away a null check, letting us create a new nullable value from an existing one. tough to mess with
time you read Java source code and encountered syntax elements like if statements, for loops, and anonymous classes, you had to pause and puzzle over what they mean. There are certain things that must be obvious to a person who wants to be a productive Java developer. Likewise there are parts of Clojure syntax that must be obvious for one to efficiently read and understand code. Examples include being comfortable with the use of let, apply, map, filter, reduce and anonymous functions...”—R. Mark Volkmann
world' string" should { "contain 11 characters" in { "Hello world" must have size(11) } "start with 'Hello'" in { "Hello world" must startWith("Hello") } "end with 'world'" in { "Hello world" must endWith("world") } } }