class Foo {
val name: String = "foo"
def print = println(s"I am $name")
} trait Vendor {
val ids: Set[Int]
val name: String
} String's and Int'sint, long, double, floata + b == b + a // Type of types
trait Numeric[A] {
// Operation:
def add(x: A, y: A): A
}
// Rule:
numeric.add(5, 1) mustEqual numeric.add(1, 5) Numeric?A, where A is able to be added// Valid
val Int = new Numeric[Int] {
def add(x: Int, y: Int) = x + y
}
val Double = new Numeric[Double] {
def add(x: Double, y: Double) = x + y
}
// Not Valid
val String = new Numeric[String] {
def add(x: String, y: String) = x + y
} Numeric is a way to categorize type:a and b, return a appended to btrait Example[A] {
def append(x: A, y: A): A
def identity: A
} trait Monoid[A] {
def mappend(x: A, y: A): A
def mzero: A
} val String = new Monoid[String] {
def mappend(x: String, y: String) = x.append(y)
def mzero = ""
}
val Int = new Monoid[Int] {
def mappend(x: Int, y: Int) = x + y
def mzero = 0
} trait Foo[A]<1> {
def op<2>(arg: A<3>): A<4>
} Seq) as a type -- which it is -- but it's really a type of types, an algebraic structureSeqtrait Functor[A] {
def map(f: A => B): Functor[B]
} A and returns BFunctor of type Btrait Functor[A] {
def map(f: A => B<1>): Functor[B]<2>
} var Foo = function(value) {
this.value = value;
}
Foo.prototype.map = function(f) { // where f is A => B
return new Foo(f(value));
}; Seq is a Functorval s: Seq[Int] = Seq(1, 2, 3)
val s2 = s.map(_.toString)
// s2.type == Seq[String] Array is a Functorvar s = [1, 2, 3];
var s2 = s.map(function(x) { return x.toString(); });
// ["1", "2", "3"] Option is a Functorval o: Option[Int] = Some(10)
val o2 = o.map(_.toString)
// o2.type == Option[String] Future is a Functorval f: Future[PoiLike] = PlaceService.getPlace(1234)
val f2 = s.map(_.mqId)
// f2.type == Future[Int] var p = $.get("/api/place/1234");
var p2 = p.pipe(function(json) {
return json.name;
}); Promise.pipe == Functor.mapfmap always returns a new Functor of B, however the behavior of when fmap "applies" can varry.sealed trait Option[A] extends Functor[A]
case class Some[A](protected val value: A) extends Option[A] {
val map(f: A => B) = Some(f(value))
}
case object None[A] extends Option[A] {
val map(f: A => B) = this
} val o: Option[String] = Some("hello")
o.map(_.toUpperCase)
// Some("HELLO")
val o2: Option[String] = None
o2.map(_.toUpperCase)
// None Functor[Functor[A]]?trait AddressLike(
country: String,
region: Option[String] = None,
locality: Option[String] = None,
...
) val cityAndState = address.locality.map { city =>
address.region.map { state =>
city + ", " + state
}
} cityAndState?Option[Option[String]]val cityAndState = address.locality.map { city =>
address.region.map { state =>
city + ", " + state
}
} val cs1 = address.locality.map { city =>
address.region.map { state =>
city + ", " + state
}
}
val cs2 = cs1.flatten
// cs1.type == Option[Option[String]]
// cs2.type == Option[String] flatMap is a shortcut for map+map+flattenval cs1 = address.locality.flatMap { city =>
address.region.map { state =>
city + ", " + state
}
}
// cs1.type == Option[String] Option[Option[String]]flatMap is technically part of a Monad which itself is a Functorfor/yield is another way of writing chained flatMap'sval o1 = Some("a")
val o2 = Some("b")
val o3 = Some("c") o1.flatMap { a =>
o2.flatMap { b =>
o3.map { c =>
a + b + c
}
}
} for {
a <- o1
b <- o2
c <- o3
} yield a + b + c flatten and flatMap are available on all Functors in Scalamap applies the given function f returning not the result of f, but a new Future such that when the value eventually resolves, f will be applied to itclass PlaceController extends Controller {
def place(id: String) = Action.async {
val futurePlace: Future[PlaceLike] = PlaceService.getPlace(id)
futurePlace.map { place =>
Ok(views.html.place(place))
}
}
} futurePlace.map { place=> Ok(views.html.place(place) ...?onSuccess and onFailure?class Future[U] {
def onSuccess[U](pf: PartialFunction[T, U]): Unit
def onFailure[U](pf: PartialFunction[T, U]): Unit
} UnitonSuccess and onFailure mutate the Future, providing it a partial function that will be called when the future resolves.
They do not return a new Future.
They are not Functor-like.
map only applies to when the future succeeds, how do we get back a new Functor when it fails?recoverdef get: Action[AnyContent] = Action.async { request =>
val p = Promise[SimpleResult]()
val f = fetchUserState(request.cookies)
f map {
...
}
f onFailure {
case e => Logger error("Recently viewed: " + e.getMessage)
}
f recover {
case _ => p success Ok
}
p future
} def get: Action[AnyContent] = Action.async { request =>
fetchUserState(request.cookies)
.map { ... }
.recover { case e =>
Logger.error("Recently viewed: " + e.getMessage)
Ok
}
} .getOrElse on Option's is stupidNoneimplicit object StringMonoid extends Monoid[String] {
def mappend(x: String, y: String) = x + y
def mzero = ""
}
implicit def safeValue[A](opt: Option[A])(implicit md: Monoid[A]): A =
opt.getOrElse(md.mzero)
val some: Option[String] = Some("asdf")
val none: Option[String] = None
println(some.toUpperCase + none.toUpperCase)
> "ASDF"
Seq based on a conditional.val s = Seq.empty
if (cond1) s = s ++ Seq(value1) else s
if (cond2) s = s ++ Seq(value1) else s
if (cond3) s = s ++ Seq(value1) else s implicit class SeqOps[A](s: Seq[A]) {
def when(cond: => Boolean)(value: A) =
if(cond) s ++ Seq(value) else s
def unless(cond: => Boolean)(value: A) =
when(!cond)(value)
def always(value: A) = when(true)(value)
} val widgets = Seq.empty
.unless(place.isInstanceOf[BizlocHotel]) { BookingWidget(...) }
.when(place.isInstanceOf[PoiLike]) { CategoryWidget(...) }
.when(place.isInstanceOf[AirportLike]) { DelaysWidget(...) }
.always { RecentlyViewedWidget(...) } s ++ Seq(value) is really Monoid AppendSeq.empty is really Monoid Identityimplicit class MonoidOps[A](origin: A) {
def when(cond: => Boolean)(value: A)(implicit md: Monoid[A]) =
if(cond) md.mappend(origin, value) else origin
def unless(cond: => Boolean)(value: A)(implicit md: Monoid[A]) =
when(!cond)(value)
def always(value: A)(implicit md: Monoid[A]) =
when(true)(value)
} def cityName(city: LocalityLike) =
city.locality
.when(city.country == "US") { city.region } Stringtrait FromString[A] {
def fromString(value: String): A
} def cityName[A](city: LocalityLike)(implicit md: Monoid[A], fs: FromString[A]) =
md.mzero
.always(fs.fromString(city.locality))
.when(city.country == "US") { fs.fromString(city.region) } cityName[String](place)
// Or
cityName[Html](place)
// Or event
cityName[Seq[String]](place)