• Monoid is a context bound for type A • Means there must be an implicit value of type Monoid[A] in implicit scope • Equivalent to: def mzget[A](opt: Option[A])( implicit m: Monoid[A]) = ~opt
• Monoid is a context bound for type A • Means there must be an implicit value of type Monoid[A] in implicit scope • Equivalent to: def mzget[A](opt: Option[A])( implicit m: Monoid[A]) = ~opt • Even supports multiple bounds: def other[A : Monoid : Functor] = ...
knowBetter(some(42)) knowBetter(none) Alias for getOrElse(sys.err(msg)) 42 throws RuntimException(“You promised!”) Good alternative to opt.get when you know it’s defined!
them? List(some(42), none, some(51)).sum error: could not find implicit value for parameter num: Numeric[Option[Int]] import scalaz.syntax.traverse._ List(some(42), none, some(51)).concatenate 93
???: F[A] 㱺 F[A 㱺 B] 㱺 F[B] • Read as... Given a function from A to B in a context F and a value of A in a context F, produce a value of B in context F.
???: F[A] 㱺 F[A 㱺 B] 㱺 F[B] • Read as... Given a function from A to B in a context F and a value of A in a context F, produce a value of B in context F. • Represents function application in a context
???: F[A] 㱺 F[A 㱺 B] 㱺 F[B] • Read as... Given a function from A to B in a context F and a value of A in a context F, produce a value of B in context F. • Represents function application in a context • Defined in http://www.soi.city.ac.uk/~ross/papers/Applicative.html
=> A) = ??? override def ap[A, B]( fa: => Option[A])(f: => Option[A => B]) = ??? } Option Is Applicative Summarized from Scalaz Seven source https://github.com/scalaz/scalaz/blob/scalaz-seven/core/src/main/scala/scalaz/Option.scala How can we lift a value of A to Option[A]?
=> A) = Some(a) override def ap[A, B]( fa: => Option[A])(f: => Option[A => B]) = ??? } Option Is Applicative Summarized from Scalaz Seven source https://github.com/scalaz/scalaz/blob/scalaz-seven/core/src/main/scala/scalaz/Option.scala How can we apply the function in Option[A=>B] to Option[A]?
=> A) = Some(a) override def ap[A, B]( fa: => Option[A])(f: => Option[A => B]) = f match { case Some(f) => fa match { case Some(x) => Some(f(x)) case None => None } case None => None } } Option Is Applicative Summarized from Scalaz Seven source https://github.com/scalaz/scalaz/blob/scalaz-seven/core/src/main/scala/scalaz/Option.scala
=> A) = Some(a) override def ap[A, B]( fa: => Option[A])(f: => Option[A => B]) = f match { case Some(f) => fa match { case Some(x) => Some(f(x)) case None => None } case None => None } } Option Is Applicative Summarized from Scalaz Seven source https://github.com/scalaz/scalaz/blob/scalaz-seven/core/src/main/scala/scalaz/Option.scala What about map[A](f: A => B): Option[B]?
F[A])(f: => F[A => B]): F[B] override def map[A, B](fa: F[A])(f: A => B): F[B] = ??? } Functor.map on Applicative Summarized from Scalaz Seven source https://github.com/scalaz/scalaz/blob/scalaz-seven/core/src/main/scala/scalaz/Option.scala Can we define map in terms of pointed and ap?
(some("Wilco") ⊛ some("Sky Blue Sky")) apply Album.apply Applicative Builder Some(Album(Wilco, Sky Blue Sky)) Companion has an apply method automatically created Alias for |@|
Monoid, Functor, Pointed, Applicative, Monad • There are many others -- ApplicativePlus, MonadPlus, Comonad, Category, Arrow, ArrowPlus, Foldable, Traversable, Monad Transformers, Reader, Writer, State, Identity, and more • These are functional design patterns • Simpler than most OO design patterns
learning these http://www.haskell.org/haskellwiki/Typeclassopedia • Scala Typeclassopedia describes the big 3 (Functor, Applicative, Monad) http://typeclassopedia.bitbucket.org/
Q: So why not just use Either? A: When Validation is constructed with an error type that has a Semigroup, there exists an Applicative Functor for Validation that accumulates errors
Validation[String, S] = v.<-: { _.getMessage } def parseUUID(s: String): Validation[Throwable, UUID] = fromTryCatch(UUID.fromString(s)) def extractId( metadata: Map[String, String]): Validation[String, UUID] = for { str <- metadata.get("id").toSuccess("No id property") id <- str |> parseUUID |> justMessage } yield id Pipe-forward operator reverses order of function application (from F#) For more info on pipe-forward, see: http://stackoverflow.com/questions/1457140/haskell-composition-vs-fs-pipe-forward-operator
to string containing keys name, level, manager, representing the name of an employee, their numeric level, and true if they are an manager and false otherwise, create an Employee containing those values if: • Name is non-empty • Level is 1 to 15 • Otherwise, report all errors in the map
{ _.parseInt |> justMessage }. flatMap { level => if (level < 1) "Level must be at least 1".fail else if (level > 15) "Really?".fail else level.success } Putting together the pieces
"17", "manager" -> "notBool")) Putting together the pieces Failure(NonEmptyList( Missing required property level, Missing required property manager)) Failure(NonEmptyList( Must have a non-empty name!, Really?, For input string: "notBool"))
List[Employee]] = { val vEmps: List[ValidationNEL[String, Employee]] = metadata map extractEmployee ??? } How can we swap order of ValidationNEL and List?
List[Employee]] = { val vEmps: List[ValidationNEL[String, Employee]] = metadata map extractEmployee vEmps.sequence[ ({type λ[a] = ValidationNEL[String, a]})#λ, Employee] } Type annotation necessary due to limitations in Scala type inferencing
{ val vEmps: List[ValidationNEL[String, Employee]] = metadata map extractEmployee vEmps.sequenceU } In this case, type params can be inferred via sequenceU
salutation: String, first: String, last: String) case class Phone( digits: String) val seth = Contact( Name("Mr.", "Seth", "Avett"), Phone("555-5555")) Lens: Problem Statement We need a copy of seth with first name set to “Scott”
= seth.copy( name = seth.name.copy(first = "Scott")) Lens: Problem Statement Doesn’t scale - each layer in record structure results in another layer of copies and duplication
lens provides the ability to focus on the specified field, which allows accessing the field value and setting the field value (immutably) • Translation: Lens = immutable getter/setter
Lens.lensu[Contact, Name]( (c, n) => c.copy(name = n), _.name) val contactPhoneLens = Lens.lensu[Contact, Phone]( (c, p) => c.copy(phone = p), _.phone) Lens Setter Getter Setter Getter •Case class lenses usually use copy in setter •Case class lenses are purely mechanical to author (there’s even a compiler plugin that does it!)
= contactNameLens >=> nameFirstLens Lens Lenses compose!! Composes 2 lenses in to a Contact to First Name lens via andThen contactFirstNameLens.get(seth) “Seth”
= contactNameLens >=> nameFirstLens Lens Lenses compose!! Composes 2 lenses in to a Contact to First Name lens via andThen contactFirstNameLens.get(seth) “Seth” contactFirstNameLens.set(seth, "Scott") Contact(Name(Mr.,Scott,Avett),Phone(555-5555))