-
-
Save ml10/a1a360792f3d775dfbd3da9cb0c9777a to your computer and use it in GitHub Desktop.
More options for avoiding mutability in Scala
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
.idea | |
*.iml | |
out | |
target | |
.DS_Store |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
name := "oc-immutability" | |
scalaVersion :="2.11.8" | |
version :="1.0" | |
libraryDependencies ++= Seq( | |
"com.typesafe.play" %% "play-json" % "2.5.8", | |
"org.scalacheck" %% "scalacheck" % "1.13.2" | |
) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
case class Course(name: String /* other fields */) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
val op = (acc: String, i: Int) => s"($i + $acc)" | |
List(1,2,3).foldLeft("(0)")(op) | |
List(2,3).foldLeft("(1 + (0))")(op) | |
List(3).foldLeft("(2 + (1 + (0)))")(op) | |
List().foldLeft("(3 + (2 + (1 + (0))))")(op) | |
"(3 + (2 + (1 + (0))))" |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
val op = (i: Int, acc: String) => s"($i + $acc)" | |
List(1,2,3).foldRight("(0)")(op) | |
op(1, List(2,3).foldRight("(0)")(op)) | |
op(1, op(2, List(3).foldRight("(0)")(op))) | |
op(1, op(2, op(3, List().foldRight("(0)")(op)))) | |
op(1, op(2, op(3, "(0)"))) | |
op(1, op(2, "(3 + (0))")) | |
op(1, "(2 + (3 + (0)))") | |
"(1 + (2 + (3 + (0))))" |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import java.time.LocalDateTime | |
import java.time.temporal.ChronoUnit | |
import scala.annotation.tailrec | |
object FoldExamples { | |
case class Item(price: BigDecimal, quantity: Int = 1 /* other fields */) | |
case class Order(items: List[Item] /* other fields */) | |
val items = List(Item(5.55), Item(3.33, 3), Item(8, 2), Item(7.75)) | |
val order = Order(items) | |
val orders = List(Order(items), Order(items)) | |
lazy val priceTotal1 = order.items.map(i => i.price * i.quantity).sum | |
lazy val priceTotal = order.items.foldLeft(BigDecimal(0))((acc, item) => (item.price * item.quantity) + acc) | |
lazy val foo = orders.flatMap(_.items.map(i => i.price * i.quantity)).sum | |
lazy val oof = orders.foldLeft(BigDecimal(0)) { (acc, order) => | |
order.items.map(i => i.price * i.quantity).sum + acc | |
} | |
lazy val applyPriceDiscount1 = priceTotal1 > 50 | |
lazy val applyPriceDiscount = priceTotal > 50 | |
// compare list vs stream | |
lazy val stress = Stream.continually(items).flatten.take(12800000).toList | |
def priceTotal1Def = { | |
val (r, time) = timeIt(stress.map(_.price).sum) | |
System.out.println(s"map sum : ${time}ms") | |
r | |
} | |
def priceTotalDef = { | |
val (r, time) = timeIt( | |
stress.foldLeft(BigDecimal(0))(_ + _.price)) | |
System.out.println(s"foldLeft: ${time}ms") | |
r | |
} | |
def timeIt[T](result: => T, unit: ChronoUnit = ChronoUnit.MILLIS): (T, Long) = { | |
val time = LocalDateTime.now() | |
(result, time.until(LocalDateTime.now(), unit)) | |
} | |
sealed trait Priority extends Product with Serializable { | |
def priority: Int | |
} | |
object Priority { | |
implicit val priorityOrdering = Ordering.by[Priority, Int](_.priority) | |
} | |
case object Low extends Priority { override val priority = 0 } | |
case object Medium extends Priority { override val priority = 5 } | |
case object High extends Priority { override val priority = 10 } | |
case object Emergency extends Priority { override val priority = 15 } | |
case class Ticket(issue: String, priority: Priority /* other fields */) | |
object Ticket { | |
implicit val ordering = Ordering.by[Ticket, Priority](_.priority) | |
} | |
val newTicketQueue = List( | |
Ticket("Light is burned out in hallway", Low), | |
Ticket("Snack supply dangerously low", Medium), | |
Ticket("Water is leaking in the kitchen", Emergency), | |
Ticket("New desks need to be assembled", Medium), | |
Ticket("Add today's guests to security system", High)) | |
def highestPri(tickets: List[Ticket]) | |
(implicit ticketOrdering: Ordering[Ticket]): List[Ticket] = { | |
val max = tickets.max | |
tickets.filter(_.priority == max.priority) | |
} | |
def morePri(tickets: List[Ticket]) | |
(implicit priorityOrdering: Ordering[Priority]): List[Ticket] = { | |
tickets.groupBy(_.priority).maxBy(_._1)._2 | |
} | |
def highestPriorityTickets(ticketQueue: List[Ticket]) | |
(implicit ticketOrdering: Ordering[Ticket]): List[Ticket] = { | |
// list z op | |
ticketQueue.foldRight(List.empty[Ticket]) { (ticket, highestPriority) => | |
highestPriority.headOption.map { head => | |
Ordering[Ticket].compare(ticket, head) match { | |
case lt if lt < 0 => highestPriority | |
case eq if eq == 0 => ticket :: highestPriority | |
case gt if gt > 0 => List(ticket) | |
} | |
} getOrElse List(ticket) | |
} | |
} | |
def mutableHighestPriority(ticketQueue: List[Ticket]) | |
(implicit ticketOrdering: Ordering[Ticket]): List[Ticket] = { | |
var highestPriority = List.empty[Ticket] // z | |
// list op | |
ticketQueue.foreach { ticket => | |
highestPriority = if (highestPriority.isEmpty) { | |
List(ticket) | |
} else { | |
val head = highestPriority.head | |
Ordering[Ticket].compare(ticket, head) match { | |
case lt if lt < 0 => highestPriority | |
case eq if eq == 0 => ticket :: highestPriority | |
case gt if gt > 0 => List(ticket) | |
} | |
} | |
} | |
highestPriority | |
} | |
val l = List(1,2,3,4,5) | |
l.foldRight(None: Option[Int])((i, found) => found.orElse(if (i % 3 == 1) Some(i) else None )) | |
def foldRight[A, B](op: (A, B) => B)(z: B)(as: Traversable[A]): B = { | |
as match { | |
case Nil => z | |
case x :: xs => op(x, foldRight(op)(z)(xs)) | |
} | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import scala.annotation.tailrec | |
// alternate, recursive implementation of foldLeft on List | |
@tailrec | |
def foldLeft[B](z: B)(op: (B, A) => B): B = { | |
this match { | |
case Nil => z | |
case x :: xs => xs.foldLeft(op(z, x))(op) | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// alternate, recursive implementation of foldRight on List | |
def foldRight[B](z: B)(op: (A, B) => B): B = { | |
this match { | |
case Nil => z | |
case x :: xs => op(x, xs.foldRight(z)(op)) | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
def highestPriority(ticketQueue: List[Ticket]) | |
(implicit ticketOrdering: Ordering[Ticket]): List[Ticket] = { | |
// list z op | |
ticketQueue.foldRight(List.empty[Ticket]) { (ticket, highestPriority) => | |
highestPriority.headOption.map { head => | |
Ordering[Ticket].compare(ticket, head) match { | |
case lt if lt < 0 => highestPriority | |
case eq if eq == 0 => ticket :: highestPriority | |
case gt if gt > 0 => List(ticket) | |
} | |
} getOrElse List(ticket) | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
def highestPriority(tickets: List[Ticket]) | |
(implicit priorityOrdering: Ordering[Priority]): List[Ticket] = { | |
tickets.groupBy(_.priority).maxBy(_._1)._2 | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
def highestPriority(tickets: List[Ticket]) | |
(implicit ticketOrdering: Ordering[Ticket]): List[Ticket] = { | |
val max = tickets.max | |
tickets.filter(_.priority == max.priority) | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
def highestPriority(ticketQueue: List[Ticket]) | |
(implicit ticketOrdering: Ordering[Ticket]): List[Ticket] = { | |
var highestPriority = List.empty[Ticket] // z | |
// list op | |
ticketQueue.foreach { ticket => | |
highestPriority = if (highestPriority.isEmpty) { | |
List(ticket) | |
} else { | |
val head = highestPriority.head | |
Ordering[Ticket].compare(ticket, head) match { | |
case lt if lt < 0 => highestPriority | |
case eq if eq == 0 => ticket :: highestPriority | |
case gt if gt > 0 => List(ticket) | |
} | |
} | |
} | |
highestPriority | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
def contains[A1 >: A](elem: A1): Boolean = { | |
val op = (contained: Boolean, i: A) => contained || i == elem | |
foldLeft(false)(op) | |
} | |
def forall(p: A => Boolean): Boolean = { | |
val op = (all: Boolean, i: A) => all && p(i) | |
foldLeft(true)(op) | |
} | |
def find[A](p: A => Boolean): Option[A] = { | |
val op = (found: Option[A], i: A) => found.orElse(if (p(i)) Some(i) else None) | |
foldLeft(None: Option[A])(op) | |
// Note partition on Traversable uses mutable values to work-around | |
// not having an addition operator, so please forgive this immutable work-around | |
def partition(p: A => Boolean): (Traversable[A], Traversable[A]) = { | |
val op = (i: A, partitioned: (Traversable[A], Traversable[A])) => { | |
val (trues, falses) = partitioned | |
if (p(i)) (Traversable(i) ++ trues, falses) else (trues, Traversable(i) ++ falses) | |
} | |
foldRight((Traversable.empty[A], Traversable.empty[A]))(op) | |
} | |
def sum[B >: A](implicit num: Numeric[B]): B = foldLeft(num.zero)(num.plus) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import java.net.InetAddress; | |
import java.net.UnknownHostException; | |
public class IPRangeChecker { | |
public static long ipToLong(InetAddress ip) { | |
byte[] octets = ip.getAddress(); | |
long result = 0; | |
for (byte octet : octets) { | |
result <<= 8; | |
result |= octet & 0xff; | |
} | |
return result; | |
} | |
public static boolean isValidRange(String ipStart, String ipEnd, | |
String ipToCheck) { | |
try { | |
long ipLo = ipToLong(InetAddress.getByName(ipStart)); | |
long ipHi = ipToLong(InetAddress.getByName(ipEnd)); | |
long ipToTest = ipToLong(InetAddress.getByName(ipToCheck)); | |
return (ipToTest >= ipLo && ipToTest <= ipHi); | |
} catch (UnknownHostException e) { | |
e.printStackTrace(); | |
return false; | |
} | |
} | |
public static void main(String[] args) { | |
System.out.println(isValidRange("122.170.122.0", "122.170.122.255", | |
"122.170.122.215")); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import java.net.InetAddress | |
import scala.util.Try | |
object IPRangeCheckerFold { | |
def ipToLong(ip: InetAddress): Long = { | |
// list z op | |
ip.getAddress.foldLeft(0L){ (acc, octet) => | |
// could also be: acc << 8 | octet & 0xff | |
val result = acc << 8 | |
result | octet & 0xff | |
} | |
} | |
def isValidRange(ipStart: String, ipEnd: String, | |
ipToCheck: String): Boolean = { | |
Try { | |
val ipLo = ipToLong(InetAddress.getByName(ipStart)) | |
val ipHi = ipToLong(InetAddress.getByName(ipEnd)) | |
val ipToTest = ipToLong(InetAddress.getByName(ipToCheck)) | |
ipToTest >= ipLo && ipToTest <= ipHi | |
}.getOrElse(false) | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import java.net.InetAddress | |
import scala.util.Try | |
object IPRangeCheckerPort { | |
def ipToLong(ip: InetAddress): Long = { | |
var result = 0l // z | |
// list op | |
ip.getAddress.foreach { octet => | |
result <<= 8 | |
result |= octet & 0xff | |
} | |
result | |
} | |
def isValidRange(ipStart: String, ipEnd: String, | |
ipToCheck: String): Boolean = { | |
Try { | |
val ipLo = ipToLong(InetAddress.getByName(ipStart)) | |
val ipHi = ipToLong(InetAddress.getByName(ipEnd)) | |
val ipToTest = ipToLong(InetAddress.getByName(ipToCheck)) | |
ipToTest >= ipLo && ipToTest <= ipHi | |
}.getOrElse(false) | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import java.net.InetAddress | |
import org.scalacheck.{Gen, Properties} | |
import org.scalacheck.Prop.forAll | |
object IPRangeCheckerSpec extends Properties("IP Range") { | |
val ipStr: Gen[String] = Gen.listOfN(4, Gen.choose(0,255)).map(_.mkString(".")) | |
val ipBounds: Gen[(String, String)] = { | |
ipStr.flatMap { ip1 => | |
ipStr.map { ip2 => | |
if (IPRangeCheckerFold.ipToLong(InetAddress.getByName(ip1)) > | |
IPRangeCheckerFold.ipToLong(InetAddress.getByName(ip2))) { | |
(ip2, ip1) | |
} else { | |
(ip1, ip2) | |
} | |
} | |
} | |
} | |
property("Converts IP Addresses Consistently Java to Scala Port") = forAll(ipBounds, ipStr) { | |
(ipBounds, ipToCheck) => | |
val (ipStart, ipEnd) = ipBounds | |
IPRangeChecker.isValidRange(ipStart, ipEnd, ipToCheck) == | |
IPRangeCheckerPort.isValidRange(ipStart, ipEnd, ipToCheck) | |
} | |
property("Converts IP Addresses Consistently Port to Fold") = forAll(ipBounds, ipStr) { | |
(ipBounds, ipToCheck) => | |
val (ipStart, ipEnd) = ipBounds | |
IPRangeCheckerPort.isValidRange(ipStart, ipEnd, ipToCheck) == | |
IPRangeCheckerFold.isValidRange(ipStart, ipEnd, ipToCheck) | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
def ipToLong(ip: java.net.InetAddress): Long = { | |
var result = 0l | |
ip.getAddress.foreach { octet => | |
result <<= 8 | |
result |= octet & 0xff | |
} | |
result | |
} | |
def ipToLongVerbose(ip: java.net.InetAddress): Long = { | |
var result = 0l | |
ip.getAddress.foreach { octet => | |
result = result * Math.pow(2,8).toLong | |
result = result + (if (octet < 0) octet.toLong + 256 else octet) | |
} | |
result | |
} | |
val ipToLongCompare = (ip: java.net.InetAddress) => { | |
val ip1 = ip.getAddress.foldLeft(0L) { (acc, octet) => | |
acc << 8 | octet & 0xff | |
} | |
val ip2 = ip.getAddress.foldLeft(0L) { (acc, octet) => | |
acc * Math.pow(2,8).toLong + (if (octet < 0) octet.toLong + 256 else octet) | |
} | |
(ip1, ip2) | |
} | |
ipToLongCompare(java.net.InetAddress.getByName("172.16.0.164")) | |
//scala> ipToLongCompare(java.net.InetAddress.getByName("172.16.0.164")) | |
//res1: (Long, Long) = (2886729892,2886729892) | |
val ipToLongVerbose = (ip: java.net.InetAddress) => { | |
ip.getAddress.foldLeft(0L) { (acc, octet) => | |
print(s"acc << 8 | octet & 0xff = ") | |
print(f"$acc%8d << 8 | $octet%3d & 0xff = ") | |
print(f"${acc << 8}%10d | ${octet & 0xff}%3d = ") | |
println(s"${acc << 8 | octet & 0xff}") | |
acc << 8 | octet & 0xff | |
} | |
} | |
ipToLongVerbose(java.net.InetAddress.getByName("172.16.0.164")) | |
//scala> ipToLongVerbose(java.net.InetAddress.getByName("172.16.0.164")) | |
//acc << 8 | octet & 0xff = 0 << 8 | -84 & 0xff = 0 | 172 = 172 | |
//acc << 8 | octet & 0xff = 172 << 8 | 16 & 0xff = 44032 | 16 = 44048 | |
//acc << 8 | octet & 0xff = 44048 << 8 | 0 & 0xff = 11276288 | 0 = 11276288 | |
//acc << 8 | octet & 0xff = 11276288 << 8 | -92 & 0xff = 2886729728 | 164 = 2886729892 | |
//res2: Long = 2886729892 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
case class Item(available: Int) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import play.api.libs.json.{Json, JsObject} | |
case class JsonIncludeValEmpty(fall: List[Course], spring: List[Course], summer: List[Course], | |
includeFall: Boolean, includeSpring: Boolean, includeSummer: Boolean) { | |
val response: JsObject = includeCourseNames(includeFall, "fall", fall) ++ | |
includeCourseNames(includeSpring, "spring", spring) ++ | |
includeCourseNames(includeSummer, "summer", summer) | |
def includeCourseNames(include: Boolean, name: String, values: List[Course]): JsObject = | |
if (include) { | |
Json.obj( | |
name -> Json.obj( | |
"list" -> Json.toJson(values.map(_.name)), | |
"count" -> values.length | |
) | |
) | |
} else { | |
Json.obj() | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import play.api.libs.json.{Json, JsObject} | |
case class JsonIncludeVar(fall: List[Course], spring: List[Course], summer: List[Course], | |
includeFall: Boolean, includeSpring: Boolean, includeSummer: Boolean) { | |
val response: JsObject = { | |
var response: JsObject = Json.obj() | |
if (includeFall) { | |
response ++= addCourses("fall", fall) | |
} | |
if (includeSpring) { | |
response ++= addCourses("spring", spring) | |
} | |
if (includeSummer) { | |
response ++= addCourses("summer", summer) | |
} | |
response | |
} | |
def addCourses(name: String, courses: List[Course]): JsObject = | |
Json.obj( | |
name -> Json.obj( | |
"list" -> Json.toJson(courses.map(_.name)), | |
"count" -> courses.length | |
) | |
) | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
case class ListIncludeConditionalExplosion(fall: List[Course], spring: List[Course], summer: List[Course], | |
includeFall: Boolean, includeSpring: Boolean, includeSummer: Boolean) { | |
val resp = if (includeFall && includeSpring && includeSummer) { | |
(fall ++ spring ++ summer).map(_.name) | |
} else if (includeFall && includeSpring) { | |
(fall ++ spring).map(_.name) | |
} else if (includeFall && includeSummer) { | |
(fall ++ summer).map(_.name) | |
} else if (includeFall) { | |
fall.map(_.name) | |
} else if (includeSpring && includeSummer) { | |
(spring ++ summer).map(_.name) | |
} else if (includeSpring) { | |
spring.map(_.name) | |
} else if (includeSummer) { | |
summer.map(_.name) | |
} else { | |
List.empty | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
case class ListIncludeValEmpty(fall: List[Course], spring: List[Course], summer: List[Course], | |
includeFall: Boolean, includeSpring: Boolean, includeSummer: Boolean) { | |
val response: List[String] = includeCourseNames(includeFall, fall) ++ | |
includeCourseNames(includeSpring, spring) ++ | |
includeCourseNames(includeSummer, summer) | |
def includeCourseNames(include: Boolean, list: List[Course]): List[String] = | |
if (include) { | |
list.map(_.name) | |
} else { | |
List.empty | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
case class ListIncludeValEmptyStep1(fall: List[Course], spring: List[Course], summer: List[Course], | |
includeFall: Boolean, includeSpring: Boolean, includeSummer: Boolean) { | |
val resp: List[String] = { | |
val fallSubList = if (includeFall) { | |
fall.map(_.name) | |
} else { | |
List.empty | |
} | |
val springSubList = if (includeSpring) { | |
spring.map(_.name) | |
} else { | |
List.empty | |
} | |
val summerSubList = if (includeSummer) { | |
summer.map(_.name) | |
} else { | |
List.empty | |
} | |
fallSubList ++ springSubList ++ summerSubList | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
case class ListIncludeVar(fall: List[Course], spring: List[Course], summer: List[Course], | |
includeFall: Boolean, includeSpring: Boolean, includeSummer: Boolean) { | |
val response: List[String] = { | |
var response: List[String] = List.empty | |
if (includeFall) { | |
response ++= fall.map(_.name) | |
} | |
if (includeSpring) { | |
response ++= spring.map(_.name) | |
} | |
if (includeSummer) { | |
response ++= summer.map(_.name) | |
} | |
response | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
case class Store(location: String, | |
hours: List[String], | |
phoneNumber: String, | |
description: String, | |
featuredItems: List[Item]) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import java.time.{DayOfWeek, LocalDate} | |
class StoreController { | |
// ... | |
def getAboutUs(storeId: Int): Store = { | |
// could be obtained from application configuration | |
val useDescriptionOfTheDay = true | |
// could be obtained from DB or cache | |
var store = getStore(storeId) | |
if (useDescriptionOfTheDay) { | |
store = store.copy(description = getDescriptionForDate(LocalDate.now())) | |
} | |
store | |
} | |
// ... | |
def getStore(id: Int): Store = { | |
Store("123 Fake St, Fakesville, Fakesota", | |
List("Su 10am - 4pm", "M-Th 8am-8pm", "Fr 8am-9pm", "Sa 9am - 9pm"), | |
"111-555-5523", | |
"Our fabulous store that sells things you didn't even know you needed!", | |
List(Item(1), Item(43))) | |
} | |
def getDescriptionForDate(date: LocalDate): String = { | |
if (date.getDayOfWeek == DayOfWeek.FRIDAY) { | |
"Join us at our store for a very special book signing today!" | |
} else { | |
"Come see our everyday low, low prices today!" | |
} | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
def getStore(i: Int): Store | |
def updateDesc(b: Boolean, s: String, st: Store): Store | |
def updateHolidayHours(hh: Option[List[String]], st: Store): Store | |
def filterFeaturedItems(i: Int, st: Store): Store |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Int => Store | |
(Boolean, Store) => Store | |
(Store) => Store | |
(Int, Store) => Store |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Int => Store | |
Boolean => Store => Store | |
Store => Store | |
Int => Store => Store |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Int => Store | |
Store => Store | |
Store => Store | |
Store => Store |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import java.time.LocalDate | |
class StoreControllerPointFree { | |
// ... | |
def getAboutUs: Int => Store = { | |
// could be obtained from application configuration | |
val useDescOfTheDay = true | |
val requiredAvailability = 5 | |
getStore | |
.andThen(updateDesc(useDescOfTheDay)) | |
.andThen(updateHolidayHours) | |
.andThen(filterFeaturedItems(requiredAvailability)) | |
} | |
// ... | |
def updateDesc(useDescOfTheDay: Boolean): Store => Store = ??? | |
def updateHolidayHours: Store => Store = ??? | |
def filterFeaturedItems(requiredAvailability: Int): Store => Store = ??? | |
def getStore: Int => Store = ??? | |
def getDescriptionForDate(date: LocalDate): String = ??? | |
def getHolidayHours(date: LocalDate): Option[List[String]] = ??? | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import java.time.LocalDate | |
class StoreControllerRefactorPhase1 { | |
// ... | |
def getAboutUs(storeId: Int): Store = { | |
// could be obtained from application configuration | |
val useDescOfTheDay = true | |
val requiredAvailability = 5 | |
// could be obtained from DB or cache | |
val store = getStore(storeId) | |
val updatedStore = updateDesc(useDescOfTheDay, store) | |
val updatedStoreWithHolidayHours = updateHolidayHours(updatedStore) | |
filterFeaturedItems(requiredAvailability, updatedStoreWithHolidayHours) | |
} | |
// ... | |
def updateDesc(useDescOfTheDay: Boolean, store: Store): Store = { | |
if (useDescOfTheDay) { | |
store.copy(description = getDescriptionForDate(LocalDate.now)) | |
} else { | |
store | |
} | |
} | |
def updateHolidayHours(store: Store): Store = { | |
getHolidayHours(LocalDate.now()).map { holidayHours => | |
store.copy(hours = holidayHours) | |
}.getOrElse(store) | |
} | |
def filterFeaturedItems(requiredAvailability: Int, store: Store): Store = { | |
store.copy(featuredItems = | |
store.featuredItems.filter(_.available >= requiredAvailability)) | |
} | |
def getStore(id: Int): Store = ??? | |
def getDescriptionForDate(date: LocalDate): String = ??? | |
def getHolidayHours(date: LocalDate): Option[List[String]] = ??? | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import java.time.LocalDate | |
class StoreControllerRefactorPhase2 { | |
// ... | |
def getAboutUs(storeId: Int): Store = { | |
// could be obtained from application configuration | |
val useDescOfTheDay = true | |
val requiredAvailability = 5 | |
val storeComposed: Int => Store = (getStore _ | |
andThen updateDesc(useDescOfTheDay) | |
andThen updateHolidayHours | |
andThen filterFeaturedItems(requiredAvailability)) | |
storeComposed(storeId) | |
} | |
// ... | |
def updateDesc(useDescOfTheDay: Boolean)(store: Store): Store = ??? | |
def updateHolidayHours(store: Store): Store = ??? | |
def filterFeaturedItems(requiredAvailability: Int)(store: Store): Store = ??? | |
def getStore(id: Int): Store = ??? | |
def getDescriptionForDate(date: LocalDate): String = ??? | |
def getHolidayHours(date: LocalDate): Option[List[String]] = ??? | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import java.time.LocalDate | |
class StoreControllerStory1 { | |
// ... | |
def getAboutUs(storeId: Int): Store = { | |
// could be obtained from application configuration | |
val useDescriptionOfTheDay = true | |
val requiredAvailability = 5 | |
// could be obtained from DB or cache | |
val store = getStore(storeId) | |
val updatedStore = if (useDescriptionOfTheDay) { | |
store.copy(description = getDescriptionForDate(LocalDate.now())) | |
} else { | |
store | |
} | |
updatedStore.copy(featuredItems = | |
updatedStore.featuredItems.filter(_.available >= requiredAvailability)) | |
} | |
// ... | |
def getStore(id: Int): Store = ??? | |
def getDescriptionForDate(date: LocalDate): String = ??? | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import java.time.LocalDate | |
class StoreControllerStory2 { | |
// ... | |
def getAboutUs(storeId: Int): Store = { | |
// could be obtained from application configuration | |
val useDescriptionOfTheDay = true | |
val requiredAvailability = 5 | |
// could be obtained from DB or cache | |
val store = getStore(storeId) | |
val updatedStore = if (useDescriptionOfTheDay) { | |
store.copy(description = getDescriptionForDate(LocalDate.now())) | |
} else { | |
store | |
} | |
val updatedStoreWithHolidayHours = getHolidayHours(LocalDate.now()).map { holidayHours => | |
updatedStore.copy(hours = holidayHours) | |
}.getOrElse(updatedStore) | |
updatedStoreWithHolidayHours.copy(featuredItems = | |
updatedStoreWithHolidayHours.featuredItems.filter(_.available >= requiredAvailability)) | |
} | |
// ... | |
def getStore(id: Int): Store = ??? | |
def getDescriptionForDate(date: LocalDate): String = ??? | |
def getHolidayHours(date: LocalDate): Option[List[String]] = { | |
if (date.getMonthValue > 10) { | |
Option(List("Su 9am - 6 pm", "M-Th 7am - 9pm", "Fri 7am - 10pm", "Sa 8am - 10pm")) | |
} else { | |
None | |
} | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import java.time.LocalDate | |
class StoreControllerVal { | |
// ... | |
def getAboutUs(storeId: Int): Store = { | |
// could be obtained from application configuration | |
val useDescriptionOfTheDay = true | |
// could be obtained from DB or cache | |
val store = getStore(storeId) | |
if (useDescriptionOfTheDay) { | |
store.copy(description = getDescriptionForDate(LocalDate.now())) | |
} else { | |
store | |
} | |
} | |
// ... | |
def getStore(id: Int): Store = ??? | |
def getDescriptionForDate(date: LocalDate): String = ??? | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
sealed trait Priority extends Product with Serializable { | |
def priority: Int | |
} | |
object Priority { | |
implicit val priorityOrdering = Ordering.by[Priority, Int](_.priority) | |
} | |
case object Low extends Priority { override val priority = 0 } | |
case object Medium extends Priority { override val priority = 5 } | |
case object High extends Priority { override val priority = 10 } | |
case object Emergency extends Priority { override val priority = 15 } | |
case class Ticket(issue: String, priority: Priority /* other fields */) | |
object Ticket { | |
implicit val ordering = Ordering.by[Ticket, Priority](_.priority) | |
} | |
val newTicketQueue = List( | |
Ticket("Light is burned out in hallway", Low), | |
Ticket("Snack supply dangerously low", Medium), | |
Ticket("Water is leaking in the kitchen", Emergency), | |
Ticket("New desks need to be assembled", Medium), | |
Ticket("Add today's guests to security system", High)) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
val totalPrice = order.items.foldLeft(BigDecimal(0)) { | |
(acc, item) => (item.price * item.quantity) + acc | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
val totalPrice = order.items.map(i => i.price * i.quantity).sum |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// from TraversableOnce.scala | |
def foldRight[B](z: B)(op: (A, B) => B): B = | |
reversed.foldLeft(z)((x, y) => op(y, x)) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment