SlideShare una empresa de Scribd logo
1 de 164
Scalaz
There’s an applicative in my functor!




Photo Credit: http://www.flickr.com/photos/yannconz/2796312310
Agenda

• Option
• Monoid
• Applicative
• Validation
• Lens
Options


• Option functions & typeclass instances
• Option syntax extensions
• Using Option with other parts of Scalaz
Constructing Options

Some(42)     Some[Int]
None         None
Constructing Options

Some(42)               Some[Int]
None                   None




import scalaz.std.option._
some(42)              Option[Int]
none[Int]             Option[Int]
Constructing Options

 Some(42)                   Some[Int]
 None                       None


Imports functions & typeclass instances for option
 import scalaz.std.option._
 some(42)              Option[Int]
 none[Int]             Option[Int]
Constructing Options
val os = List(Some(42), None, Some(20))

os.foldLeft(None) { (acc, o) => acc orElse o }
Constructing Options
val os = List(Some(42), None, Some(20))

os.foldLeft(None) { (acc, o) => acc orElse o }
error: type mismatch;
 found   : Option[Int]
 required: None.type
  os.foldLeft(None) { (acc, o) => acc orElse o }
                                      ^
Constructing Options
val os = List(Some(42), None, Some(20))

os.foldLeft(None) { (acc, o) => acc orElse o }
error: type mismatch;
 found   : Option[Int]
 required: None.type
  os.foldLeft(None) { (acc, o) => acc orElse o }
                                      ^


os.foldLeft(None: Option[Int]) { (acc, o) => acc orElse o }
                                               Some(42)
Constructing Options
val os = List(Some(42), None, Some(20))

os.foldLeft(None) { (acc, o) => acc orElse o }
error: type mismatch;
 found   : Option[Int]
 required: None.type
  os.foldLeft(None) { (acc, o) => acc orElse o }
                                      ^


os.foldLeft(None: Option[Int]) { (acc, o) => acc orElse o }
                                               Some(42)
os.foldLeft(none[Int]) { (acc, o) => acc orElse o }

                                               Some(42)
Option conditional

import scalaz.syntax.std.option._

def xget(opt: Option[Int]) =
  opt | Int.MaxValue

xget(Some(42))
xget(None)
Option conditional
Imports syntax extensions for option


import scalaz.syntax.std.option._

def xget(opt: Option[Int]) =
  opt | Int.MaxValue

xget(Some(42))
xget(None)
Option conditional
            Alias for getOrElse


import scalaz.syntax.std.option._

def xget(opt: Option[Int]) =
  opt | Int.MaxValue

xget(Some(42))
xget(None)
Option conditional

import scalaz.syntax.std.option._

def xget(opt: Option[Int]) =
  opt | Int.MaxValue

xget(Some(42))   42
                 214748364
xget(None)
                 7
Option unary ~

import scalaz.std.anyVal._
import scalaz.std.option._
import scalaz.syntax.std.option._

def zget(opt: Option[Int]) = ~opt
zget(Some(42))
zget(None)
Option unary ~
Imports functions & typeclass instances for int, float,
etc.

import scalaz.std.anyVal._
import scalaz.std.option._
import scalaz.syntax.std.option._

def zget(opt: Option[Int]) = ~opt
zget(Some(42))
zget(None)
Option unary ~
          Alias for getOrElse(zero)


import scalaz.std.anyVal._
import scalaz.std.option._
import scalaz.syntax.std.option._

def zget(opt: Option[Int]) = ~opt
zget(Some(42))
zget(None)
Option unary ~
          Alias for getOrElse(zero)


import scalaz.std.anyVal._
import scalaz.std.option._
import scalaz.syntax.std.option._

def zget(opt: Option[Int]) = ~opt
zget(Some(42))   42
zget(None)        0
Option unary ~
          Alias for getOrElse(zero)


import scalaz.std.anyVal._
import scalaz.std.option._
import scalaz.syntax.std.option._

def zget(opt: Option[Int]) = ~opt
zget(Some(42))   42
zget(None)        0
                   Where does zero come from?
Option unary ~

import scalaz.Monoid
import scalaz.std.string._
import scalaz.std.list._

def mzget[A : Monoid](opt: Option[A]) = ~opt
mzget(none[Int])         0
mzget(none[String])      “”
mzget(none[List[Int]])   List()
Aside: Context Bounds
def mzget[A : Monoid](opt: Option[A]) = ~opt
Aside: Context Bounds
def mzget[A : Monoid](opt: Option[A]) = ~opt

 • Monoid is a context bound for type A
Aside: Context Bounds
def mzget[A : Monoid](opt: Option[A]) = ~opt

 • Monoid is a context bound for type A
 • Means there must be an implicit value of type
   Monoid[A] in implicit scope
Aside: Context Bounds
def mzget[A : Monoid](opt: Option[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
Aside: Context Bounds
def mzget[A : Monoid](opt: Option[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 other[A multiple bounds:
   def
        supports
                 : Monoid : Functor]       = ...
Option err


def knowBetter[A](opt: Option[A]) =
  opt err "You promised!"

knowBetter(some(42))
knowBetter(none)
Option err
          Alias for getOrElse(sys.err(msg))



  def knowBetter[A](opt: Option[A]) =
    opt err "You promised!"

  knowBetter(some(42))      42
  knowBetter(none)
            throws RuntimException(“You promised!”)


Good alternative to opt.get when you know it’s defined!
Option fold/cata

import java.net.InetAddress
def ipAddress(opt: Option[InetAddress]) =
  opt.fold(_.getHostAddress, "0.0.0.0")

ipAddress(Some(InetAddress.getLocalHost))

ipAddress(None)
Option fold/cata
   Replacement for matching on Some/None


import java.net.InetAddress
def ipAddress(opt: Option[InetAddress]) =
  opt.fold(_.getHostAddress, "0.0.0.0")

ipAddress(Some(InetAddress.getLocalHost))
                                    10.0.1.1
ipAddress(None)                     2
                                    0.0.0.0
Option ifNone


var cnt = 0
some(42) ifNone { cnt += 1 }
none ifNone { cnt += 1 }
println(cnt)
Concatenate

Given a list of options, how do you sum them?
List(some(42), none, some(51)).sum
error: could not find implicit value for
parameter num: Numeric[Option[Int]]
Concatenate

Given a list of options, how do you sum 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
Sequence

Given a list of options, how do you get option of list?
List(some(42), none, some(51)).sequence
                        None
List(some(42), some(51)).sequence
                               Some(List(42, 51))
Semigroup & Monoid Review
                               Not Scala syntax!



  • SemigroupA
    append:       A   A


  • Monoid extends Semigroup
    zero: A
Syntax

import scalaz.std.anyVal._
import scalaz.syntax.monoid._

1 |+| 2                               3


import scalaz.std.list._

List(1, 2) |+| List(3, 4)       List(1, 2, 3,
                                4)
Syntax
import scalaz.std.map._
import scalaz.std.set._

val low = Map(
  'odd -> Set(1, 3),
  'even -> Set(2, 4))
val hi = Map(
  'odd -> Set(5, 7),
  'even -> Set(6, 8))
low |+| hi
Syntax
import scalaz.std.map._
import scalaz.std.set._

val low = Map(
  'odd -> Set(1, 3),
  'even -> Set(2, 4))
val hi = Map(
  'odd -> Set(5, 7),
  'even -> Set(6, 8))
low |+| hi
                        Map(‘odd -> Set(1, 3, 5, 7),
                        ‘even -> Set(2, 4, 6, 8))
Option is Monoid


• There’s a monoid of Option[A] if A is a
  Semigroup
  • zero = None
  • append = ???
Option is Monoid

implicit def optionMonoid[A: Semigroup]: Monoid[Option[A]] =
  new Monoid[Option[A]] {
    def append(f1: Option[A], f2: => Option[A]) = (f1, f2) match {
      case (Some(a1), Some(a2)) =>
        Some(Semigroup[A].append(a1, a2))
      case (Some(a1), None)     => f1
      case (None, Some(a2))     => f2
      case (None, None)         => None
    }

      def zero: Option[A] = None
  }



                                   From Scalaz Seven source
 https://github.com/scalaz/scalaz/blob/scalaz-seven/core/src/main/scala/scalaz/std/Option.scala
Option is Monoid


import scalaz.syntax.monoid._

some(20) |+| none |+| some(22)   Some(42)
Option alternative monoids

  • Can we find other monoids for Option?
  • Must implement zero and append
  • But remember the monoid laws:
   • Closure
   • Associativity
   • Identity
          See: http://en.wikipedia.org/wiki/Monoid
Option alternative monoids

  • Keep everything the same as semigroup
    based monoid but focus on:
    case (Some(a1), Some(a2)) =>


  • Left
    case (Some(a1), Some(a2)) => f1


  • Right
    case (Some(a1), Some(a2)) => f2
Option alternative monoids

some(20).first |+| none.first |+|
some(22).first
                           Some(20)

some(20).last |+| none.last |+|
some(22).last
                           Some(22)
Functor & Monad Review
                            Not Scala syntax!


• Functor
  map: F[A]     (A    B)    F[B]


• Monad extendsM[A]
  point: A
                Functor

  flatMap: M[A]      (A    M[B])    M[B]
Functor & Monad Review
                                         Not Scala syntax!


• Functor
  map: F[A]           (A         B)      F[B]
 Option[Int]   (Int   String)    Option[String]


• Monad extendsM[A]
  point: A
                Functor

  flatMap: M[A]                 (A     M[B])      M[B]
Functor & Monad Review
                                         Not Scala syntax!


• Functor
  map: F[A]           (A         B)      F[B]
 Option[Int]   (Int   String)    Option[String]


• Monad extendsM[A]
  point: A
                Functor

  flatMap: M[A]                 (A     M[B])      M[B]
Functor & Monad Review
                                              Not Scala syntax!


• Functor
  map: F[A]              (A          B)           F[B]
 Option[Int]   (Int      String)     Option[String]


• Monad extendsM[A]
  point: A
                Functor

  flatMap: M[A]                    (A       M[B])          M[B]
 String   Option[String]
 Option[String]       (String      Option[Int])    Option[Int]
What’s this?
• ??? extends Functor
  point: A      F[A]
  ???: F[A]      F[A    B]   F[B]
What’s this?
• ??? extends Functor
  point: A        F[A]
  ???: 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.
What’s this?
• ??? extends Functor
  point: A        F[A]
  ???: 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
What’s this?
• ??? extends Functor
  point: A           F[A]
  ???: 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
Applicative
• Applicative extends Functor
  point: A                  F[A]
  ap: F[A]                  F[A                 B]               F[B]




                                    Summarized from Scalaz Seven source
          https://github.com/scalaz/scalaz/blob/scalaz-seven/core/src/main/scala/scalaz/Pointed.scala
        https://github.com/scalaz/scalaz/blob/scalaz-seven/core/src/main/scala/scalaz/Applicative.scala
Applicative
• Applicative extends Functor
  point: A                   F[A]
  ap: F[A]                   F[A                 B]               F[B]


• Or in proper Scala:
  trait Pointed[F[_]] extends Functor[F] {
    def point[A](a: => A): F[A]
  }

  trait Applicative[F[_]] extends Functor[F] with Pointed[F] {
    def ap[A,B](fa: => F[A])(f: => F[A => B]): F[B]
  }

                                     Summarized from Scalaz Seven source
           https://github.com/scalaz/scalaz/blob/scalaz-seven/core/src/main/scala/scalaz/Pointed.scala
         https://github.com/scalaz/scalaz/blob/scalaz-seven/core/src/main/scala/scalaz/Applicative.scala
Option Is Applicative
    Let’s define an applicative instance for Option



implicit val optionInstance = new Applicative[Option] {
  override def point[A](a: => A) = ???
  override def ap[A, B](
    fa: => Option[A])(f: => Option[A => B]) = ???
}




                                   Summarized from Scalaz Seven source
         https://github.com/scalaz/scalaz/blob/scalaz-seven/core/src/main/scala/scalaz/Option.scala
Option Is Applicative
    How can we lift a value of A to Option[A]?



implicit val optionInstance = new Applicative[Option] {
  override def point[A](a: => A) = ???
  override def ap[A, B](
    fa: => Option[A])(f: => Option[A => B]) = ???
}




                                   Summarized from Scalaz Seven source
         https://github.com/scalaz/scalaz/blob/scalaz-seven/core/src/main/scala/scalaz/Option.scala
Option Is Applicative


implicit val optionInstance = new Applicative[Option] {
  override def point[A](a: => A) = Some(a)
  override def ap[A, B](
    fa: => Option[A])(f: => Option[A => B]) = ???
}




                                   Summarized from Scalaz Seven source
         https://github.com/scalaz/scalaz/blob/scalaz-seven/core/src/main/scala/scalaz/Option.scala
Option Is Applicative
           How can we apply the function in
           Option[A=>B] to Option[A]?


implicit val optionInstance = new Applicative[Option] {
  override def point[A](a: => A) = Some(a)
  override def ap[A, B](
    fa: => Option[A])(f: => Option[A => B]) = ???
}




                                   Summarized from Scalaz Seven source
         https://github.com/scalaz/scalaz/blob/scalaz-seven/core/src/main/scala/scalaz/Option.scala
Option Is Applicative
implicit val optionInstance = new Applicative[Option] {
  override def point[A](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
  }
}



                                   Summarized from Scalaz Seven source
         https://github.com/scalaz/scalaz/blob/scalaz-seven/core/src/main/scala/scalaz/Option.scala
Option Is Applicative
implicit val optionInstance = new Applicative[Option] {
  override def point[A](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
  }
}
                    What about map[A](f: A => B): Option[B]?

                                    Summarized from Scalaz Seven source
          https://github.com/scalaz/scalaz/blob/scalaz-seven/core/src/main/scala/scalaz/Option.scala
Functor.map on Applicative
    Can we define map in terms of pointed and
    ap?



trait Applicative[F[_]] extends Functor[F] with Pointed[F] {
  def ap[A,B](fa: => F[A])(f: => F[A => B]): F[B]
  override def map[A, B](fa: F[A])(f: A => B): F[B] =
    ???
}




                                     Summarized from Scalaz Seven source
           https://github.com/scalaz/scalaz/blob/scalaz-seven/core/src/main/scala/scalaz/Option.scala
Functor.map on Applicative


trait Applicative[F[_]] extends Functor[F] with Pointed[F] {
  def ap[A,B](fa: => F[A])(f: => F[A => B]): F[B]
  override def map[A, B](fa: F[A])(f: A => B): F[B] =
    ap(fa)(point(f))
}




                                     Summarized from Scalaz Seven source
           https://github.com/scalaz/scalaz/blob/scalaz-seven/core/src/main/scala/scalaz/Option.scala
Applicative Usage


import scalaz.std.option._
import scalaz.syntax.applicative._

val oa5: Option[Int => Int] = Some((_: Int) + 5)
some(15) <*> oa5
Applicative Usage


import scalaz.std.option._
import scalaz.syntax.applicative._

val oa5: Option[Int => Int] = Some((_: Int) + 5)
some(15) <*> oa5


   Alias for ap
Applicative Usage


import scalaz.std.option._
import scalaz.syntax.applicative._

val oa5: Option[Int => Int] = Some((_: Int) + 5)
some(15) <*> oa5
                                     Some(20)

   Alias for ap
Applicative Usage

import scalaz.std.option._
import scalaz.syntax.applicative._

some(15).<**>(some(5)) { _ + _ }

some(15).<***>(some(5), some(6)) { _ + _ + _ }

some(15).<****>(some(5), some(6), some(7)) {
  _ + _ + _ + _ }
Applicative Usage

import scalaz.std.option._
import scalaz.syntax.applicative._

some(15).<**>(some(5)) { _ + _ }                 Some(20)
some(15).<***>(some(5), some(6)) { _ + _ + _ }   Some(26)
some(15).<****>(some(5), some(6), some(7)) {     Some(33)
  _ + _ + _ + _ }
Applicative Builder
         Most common and convenient
         usage

import scalaz.std.option._
import scalaz.syntax.applicative._

(some(15) |@| some(5)) apply { _ + _ }

(some(15) |@| some(5) |@| some(6)) apply { _ + _ + _ }

(some(15) |@| some(5)).tupled
Applicative Builder
         Most common and convenient
         usage

import scalaz.std.option._
import scalaz.syntax.applicative._

(some(15) |@| some(5)) apply { _ + _ }
                                                Some(20)
(some(15) |@| some(5) |@| some(6)) apply { _ + _ + _ }

(some(15) |@| some(5)).tupled
                                                Some(26)

                                            Some((15, 5))
Applicative Builder
         Most common and convenient
         usage

import scalaz.std.option._
import scalaz.syntax.applicative._

(some(15) |@| some(5)) apply { _ + _ }
                                                Some(20)
(some(15) |@| some(5) |@| some(6)) apply { _ + _ + _ }

(some(15) |@| some(5)).tupled
                                                Some(26)

                                            Some((15, 5))
             Supports up to 12 arguments
Applicative Builder


import scalaz.std.option._
import scalaz.syntax.applicative._

case class Album(name: String, artist: String)

(some("Wilco") ⊛ some("Sky Blue Sky")) apply Album.apply
Applicative Builder

                                          Companion has an
                                          apply method
import scalaz.std.option._                automatically created
import scalaz.syntax.applicative._

case class Album(name: String, artist: String)

(some("Wilco") ⊛ some("Sky Blue Sky")) apply Album.apply
Applicative Builder

                                          Companion has an
                                          apply method
import scalaz.std.option._                automatically created
import scalaz.syntax.applicative._

case class Album(name: String, artist: String)

(some("Wilco") ⊛ some("Sky Blue Sky")) apply Album.apply


      Alias for |@|
Applicative Builder

                                              Companion has an
                                              apply method
import scalaz.std.option._                    automatically created
import scalaz.syntax.applicative._

case class Album(name: String, artist: String)

(some("Wilco") ⊛ some("Sky Blue Sky")) apply Album.apply

                      Some(Album(Wilco, Sky Blue Sky))
      Alias for |@|
Why Applicatives?

• Less restrictive than Monads, and thus,
  more general (powerful)
• Composable
  http://blog.tmorris.net/monads-do-not-compose/


• Support parallel computation
  More on this point later...
A word on typeclasses
• So far we’ve seen Semigroup, Monoid, Functor,
  Pointed, Applicative, Monad
A word on typeclasses
• So far we’ve seen Semigroup, 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
A word on typeclasses
• So far we’ve seen Semigroup, 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
Some Haskell Typeclasses




                         Credit: Typeclassopedia
     http://www.haskell.org/haskellwiki/Typeclassopedia#Introduction
Typeclass References

• Haskell Typeclassopedia is a great reference for
  learning these
  http://www.haskell.org/haskellwiki/Typeclassopedia


• Scala Typeclassopedia describes the big 3 (Functor,
  Applicative, Monad)
  http://typeclassopedia.bitbucket.org/
Validation

sealed trait Validation[+E, +A] {
  ...
}

final case class Success[E, A](a: A)
  extends Validation[E, A]

final case class Failure[E, A](e: E)
  extends Validation[E, A]
Validation

• Represents either success or failure
• On success, provides the successful value
• On failure, provides the failure value
• Sound familiar?
Isomorphic to Either

        ≅
Isomorphic to Either
Validation       Either

  Success
             ≅   Right

  Failure        Left
Isomorphic to Either
 Validation                      Either

    Success
                      ≅          Right

    Failure                      Left


Q: So why not just use Either?
Isomorphic to Either
 Validation                         Either

    Success
                      ≅             Right

    Failure                         Left


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
Constructing Validations
import scalaz.{Success, Failure}
Success(42)                  Success[Nothing, Int]
Failure("boom")               Failure[String, Nothing]
Constructing Validations
import scalaz.{Success, Failure}
Success(42)                  Success[Nothing, Int]
Failure("boom")               Failure[String, Nothing]

import scalaz.Validation
Validation.success(42)             Validation[Nothing, Int]
Validation.failure("boom")         Validation[String, Nothing]
Constructing Validations
import scalaz.{Success, Failure}
Success(42)                  Success[Nothing, Int]
Failure("boom")               Failure[String, Nothing]

import scalaz.Validation
Validation.success(42)             Validation[Nothing, Int]
Validation.failure("boom")         Validation[String, Nothing]

import scalaz.syntax.validation._
42.success                   Validation[Nothing, Int]
"boom".fail                  Validation[String, Nothing]
Constructing Validations
import scalaz.{Success, Failure}
Success(42)                  Success[Nothing, Int]
Failure("boom")               Failure[String, Nothing]

import scalaz.Validation
Validation.success(42)             Validation[Nothing, Int]
Validation.failure("boom")         Validation[String, Nothing]

import scalaz.syntax.validation._
42.success                   Validation[Nothing, Int]
"boom".fail                  Validation[String, Nothing]

42.success[String]                 Validation[String, Int]
"boom".fail[Int]                   Validation[String, Int]
Option to Validation

import scalaz.std.option._
import scalaz.syntax.std.option._

some(42).toSuccess("boom")
none[Int].toSuccess("boom")

some(42).toFailure("boom")
none[Int].toFailure("boom")
Option to Validation

import scalaz.std.option._
import scalaz.syntax.std.option._

some(42).toSuccess("boom")      Success(42)
none[Int].toSuccess("boom")     Failure(“boom”)


some(42).toFailure("boom")
none[Int].toFailure("boom")
Option to Validation

import scalaz.std.option._
import scalaz.syntax.std.option._

some(42).toSuccess("boom")      Success(42)
none[Int].toSuccess("boom")     Failure(“boom”)


some(42).toFailure("boom")      Failure(42)
none[Int].toFailure("boom")     Success(“boom”)
Either to Validation


import scalaz.syntax.id._
import scalaz.Validation.fromEither

fromEither(42.right)
fromEither("boom".left)
Either to Validation


import scalaz.syntax.id._
import scalaz.Validation.fromEither

fromEither(42.right)            Success(42)
fromEither("boom".left)         Failure(“boom”)
Throwing to Validation
import scalaz.Validation.fromTryCatch

fromTryCatch("42".toInt)
fromTryCatch("notAnInt".toInt)
Throwing to Validation
import scalaz.Validation.fromTryCatch

fromTryCatch("42".toInt)
fromTryCatch("notAnInt".toInt)
Success(42)
Failure(java.lang.NumberFormatException: For input string: "notAnInt")
Throwing to Validation
import scalaz.Validation.fromTryCatch

fromTryCatch("42".toInt)
fromTryCatch("notAnInt".toInt)
Success(42)
Failure(java.lang.NumberFormatException: For input string: "notAnInt")


fromTryCatch("notAnInt".toInt)
  .fail.map { _.getMessage }.validation
Throwing to Validation
import scalaz.Validation.fromTryCatch

fromTryCatch("42".toInt)
fromTryCatch("notAnInt".toInt)
Success(42)
Failure(java.lang.NumberFormatException: For input string: "notAnInt")


fromTryCatch("notAnInt".toInt)
  .fail.map { _.getMessage }.validation

Failure(For input string: "notAnInt")
Mapping via Bifunctor
import scalaz.syntax.bifunctor._
Bifunctor = functor of 2 arguments

fromTryCatch("notAnInt".toInt).
  <-: { _.getMessage }     <-: = Map left value
Mapping via Bifunctor
import scalaz.syntax.bifunctor._
Bifunctor = functor of 2 arguments

fromTryCatch("notAnInt".toInt).
  <-: { _.getMessage }     <-: = Map left value
Failure(For input string: "notAnInt")
Mapping via Bifunctor
import scalaz.syntax.bifunctor._
Bifunctor = functor of 2 arguments

fromTryCatch("notAnInt".toInt).
  <-: { _.getMessage }     <-: = Map left value
Failure(For input string: "notAnInt")



fromTryCatch("notAnInt".toInt).
  bimap(_.getMessage, identity)
Mapping via Bifunctor
import scalaz.syntax.bifunctor._
Bifunctor = functor of 2 arguments

fromTryCatch("notAnInt".toInt).
  <-: { _.getMessage }     <-: = Map left value
Failure(For input string: "notAnInt")



fromTryCatch("notAnInt".toInt).
  bimap(_.getMessage, identity)

Failure(For input string: "notAnInt")
Validation is Monad
def justMessage[S](
  v: Validation[Throwable, S]): Validation[String, S] =
  v.<-: { _.getMessage }

def extractId(
  metadata: Map[String, String]): Validation[String, UUID] =
  for {
    str <- metadata.get("id").toSuccess("No id property")
    id <- justMessage(fromTryCatch(UUID.fromString(str)))
  } yield id

extractId(Map.empty)
extractId(Map("id" -> "notUuid"))
extractId(Map("id" -> UUID.randomUUID.toString))
Validation is Monad
def justMessage[S](
  v: Validation[Throwable, S]): Validation[String, S] =
  v.<-: { _.getMessage }

def extractId(
  metadata: Map[String, String]): Validation[String, UUID] =
  for {
    str <- metadata.get("id").toSuccess("No id property")
    id <- justMessage(fromTryCatch(UUID.fromString(str)))
  } yield id

extractId(Map.empty)
extractId(Map("id" -> "notUuid"))
extractId(Map("id" -> UUID.randomUUID.toString))


            Failure(No id property)
            Failure(Invalid UUID string: notUuid)
            Success(f6af15db-feeb-4895-8c67-a70a6f947db9)
Aside: Monadic DSL
def justMessage[S](
  v: Validation[Throwable, S]): Validation[String, S] =
  v.<-: { _.getMessage }

def extractId(
  metadata: Map[String, String]): Validation[String, UUID] =
  for {
    str <- metadata.get("id").toSuccess("No id property")
    id <- justMessage(fromTryCatch(UUID.fromString(str)))
  } yield id

extractId(Map.empty)
extractId(Map("id" -> "notUuid"))
extractId(Map("id" -> UUID.randomUUID.toString))



               This reads pretty naturally!
Aside: Monadic DSL
def justMessage[S](
  v: Validation[Throwable, S]): Validation[String, S] =
  v.<-: { _.getMessage }

def extractId(
  metadata: Map[String, String]): Validation[String, UUID] =
  for {
    str <- metadata.get("id").toSuccess("No id property")
    id <- justMessage(fromTryCatch(UUID.fromString(str)))
  } yield id

extractId(Map.empty)
extractId(Map("id" -> "notUuid"))
extractId(Map("id" -> UUID.randomUUID.toString))



         This doesn’t! Notation is inside-out!
Aside: Monadic DSL
import scalaz.syntax.id._

def justMessage[S](
  v: Validation[Throwable, S]): 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
Validation

• Monadic usage of Validation is incredibly
  useful
  • As useful as monadic option but provides
    why failures have occurred
• Can it get better?
Validation is Applicative...
          ... if the error type is Semigroup
Validation is Applicative...
                     ... if the error type is Semigroup

Which of these are applicative?

           Validation[Int, Any]

           Validation[Any, Int]

           Validation[List[String], String]

           Validation[String, Int]
Validation is Applicative...
                     ... if the error type is Semigroup

Which of these are applicative?

        ✔ Validation[Int, Any]
           Validation[Any, Int]

           Validation[List[String], String]

           Validation[String, Int]
Validation is Applicative...
                     ... if the error type is Semigroup

Which of these are applicative?

        ✔ Validation[Int, Any]

        ✘ Validation[Any, Int]
           Validation[List[String], String]

           Validation[String, Int]
Validation is Applicative...
                     ... if the error type is Semigroup

Which of these are applicative?

        ✔ Validation[Int, Any]

        ✘ Validation[Any, Int]

        ✔ Validation[List[String], String]
           Validation[String, Int]
Validation is Applicative...
                     ... if the error type is Semigroup

Which of these are applicative?

        ✔ Validation[Int, Any]

        ✘ Validation[Any, Int]

        ✔ Validation[List[String], String]

        ✔ Validation[String, Int]
Validation[List[_], _]
Validation[List[String], Int]
Validation[List[_], _]
Validation[List[String], Int]

  Success(42)
Validation[List[_], _]
Validation[List[String], Int]

  Success(42)

  Failure(List(“Tigers”, “Lions”, “Bears”))
Validation[List[_], _]
Validation[List[String], Int]

  Success(42)

  Failure(List(“Tigers”, “Lions”, “Bears”))

  Failure(List())
Validation[List[_], _]
Validation[List[String], Int]

  Success(42)

  Failure(List(“Tigers”, “Lions”, “Bears”))

  Failure(List())
                      Failure of no errors?
                      Can we do better?
                      Use the type system?
ValidationNEL
Validation[NonEmptyList[String], Int]
  Success(42)

  Failure(NonEmptyList(
    “Tigers”, “Lions”, “Bears”))
ValidationNEL
Validation[NonEmptyList[String], Int]
   Success(42)

   Failure(NonEmptyList(
     “Tigers”, “Lions”, “Bears”))

This is so common, there’s an alias for it:
                       ValidationNEL[String, Int]
ValidationNEL
Validation[NonEmptyList[String], Int]
   Success(42)

   Failure(NonEmptyList(
     “Tigers”, “Lions”, “Bears”))

This is so common, there’s an alias for it:
                       ValidationNEL[String, Int]

And any Validation[E, S] can be converted to
ValidationNEL[E, S]:
                                  v.toValidationNEL
Putting together the pieces
 • Given a map of string 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
Putting together the pieces


   case class Employee(
     name: String,
     level: Int,
     manager: Boolean)

   type Metadata = Map[String, String]
Putting together the pieces

def justMessage[S](
  v: Validation[Throwable, S]): Validation[String, S] =
  v.<-: { _.getMessage }




def extractString(
  metadata: Metadata,
  key: String): Validation[String, String] =
  metadata.
    get(key).
    toSuccess("Missing required property %s".format(key))
Putting together the pieces

def extractName(
  metadata: Metadata): Validation[String, String] =
  extractString(metadata, "name") flatMap { name =>
    if (name.isEmpty) "Must have a non-empty name!".fail
    else name.success
  }
Putting together the pieces

def extractLevel(
  metadata: Metadata): Validation[String, Int] =
  extractString(metadata, "level").
    flatMap { _.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


def extractManager(
  metadata: Metadata): Validation[String, Boolean] =
  extractString(metadata, "manager").
    flatMap { _.parseBoolean |> justMessage }
Putting together the pieces


def extractEmployee(
  metadata: Metadata): ValidationNEL[String, Employee] = {
  extractName(metadata).toValidationNel |@|
  extractLevel(metadata).toValidationNel |@|
  extractManager(metadata).toValidationNel
} apply Employee.apply
Putting together the pieces
extractEmployee(Map(
  "name" -> "Turing",
  "level" -> "15",
  "manager" -> "false"))


extractEmployee(Map(
  "name" -> "Turing",
  "level" -> "0",
  "manager" -> "true"))


extractEmployee(Map(
  "name" -> "Turing",
  "level" -> "17",
  "manager" -> "true"))
Putting together the pieces
extractEmployee(Map(
  "name" -> "Turing",      Success(Employee(Turing,15,false))
  "level" -> "15",
  "manager" -> "false"))


extractEmployee(Map(
  "name" -> "Turing",
  "level" -> "0",
  "manager" -> "true"))


extractEmployee(Map(
  "name" -> "Turing",
  "level" -> "17",
  "manager" -> "true"))
Putting together the pieces
extractEmployee(Map(
  "name" -> "Turing",      Success(Employee(Turing,15,false))
  "level" -> "15",
  "manager" -> "false"))


extractEmployee(Map(
  "name" -> "Turing",          Failure(NonEmptyList(Level
  "level" -> "0",              must be at least 1))
  "manager" -> "true"))


extractEmployee(Map(
  "name" -> "Turing",
  "level" -> "17",
  "manager" -> "true"))
Putting together the pieces
extractEmployee(Map(
  "name" -> "Turing",      Success(Employee(Turing,15,false))
  "level" -> "15",
  "manager" -> "false"))


extractEmployee(Map(
  "name" -> "Turing",          Failure(NonEmptyList(Level
  "level" -> "0",              must be at least 1))
  "manager" -> "true"))


extractEmployee(Map(
  "name" -> "Turing",
  "level" -> "17",          Failure(NonEmptyList(Really?))
  "manager" -> "true"))
Putting together the pieces

extractEmployee(Map(
  "name" -> "Turing"))




extractEmployee(Map(
  "name" -> "",
  "level" -> "17",
  "manager" -> "notBool"))
Putting together the pieces

extractEmployee(Map(         Failure(NonEmptyList(
  "name" -> "Turing"))        Missing required property level,
                              Missing required property manager))



extractEmployee(Map(
  "name" -> "",
  "level" -> "17",
  "manager" -> "notBool"))
Putting together the pieces

extractEmployee(Map(         Failure(NonEmptyList(
  "name" -> "Turing"))        Missing required property level,
                              Missing required property manager))



extractEmployee(Map(         Failure(NonEmptyList(
  "name" -> "",               Must have a non-empty name!,
  "level" -> "17",            Really?,
  "manager" -> "notBool"))    For input string: "notBool"))
Putting together the pieces


 • Building upon previous example, given a list
   of metadata, produce a list of employees or a
   list of errors
Putting together the pieces


def extractEmployees(
  metadata: List[Metadata]
): ValidationNEL[String, List[Employee]] = ???
Putting together the pieces

def extractEmployees(
  metadata: List[Metadata]
): ValidationNEL[String, List[Employee]] = {


    val vEmps: List[ValidationNEL[String, Employee]] =
      metadata map extractEmployee

    ???
}
Putting together the pieces

def extractEmployees(
  metadata: List[Metadata]
): ValidationNEL[String, List[Employee]] = {
                           How can we swap order of
                           ValidationNEL and List?
  val vEmps: List[ValidationNEL[String, Employee]] =
    metadata map extractEmployee

    ???
}
Putting together the pieces

def extractEmployees(
  metadata: List[Metadata]
): ValidationNEL[String, 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
Type Lambdas



sequence[({type λ[a] = ValidationNEL[String, a]})#λ, Employee]
Type Lambdas



sequence[({type λ[a] = ValidationNEL[String, a]})#λ, Employee]

   Defines an anonymous structural type with one member, λ[a]
Type Lambdas



sequence[({type λ[a] = ValidationNEL[String, a]})#λ, Employee]

      Defines type λ[a] as an alias for ValidationNEL[String, a]
Type Lambdas



sequence[({type λ[a] = ValidationNEL[String, a]})#λ, Employee]

          References the λ member of the structural type
Type Lambdas



    sequence[λ[a] = ValidationNEL[String, a], Employee]

Not valid Scala syntax, but IntelliJ will render type lambdas this way
Type Lambdas



sequence[ValidationNEL[String, _], Employee]

      Can be thought of this way (sort of)
Lens: Problem Statement
case class Contact(
  name: Name,
  phone: Phone)

case class Name(
  salutation: String,
  first: String,
  last: String)

case class Phone(
  digits: String)

val seth = Contact(
  Name("Mr.", "Seth", "Avett"), Phone("555-5555"))
Lens: Problem Statement
case class Contact(
  name: Name,
  phone: Phone)
                            We need a copy of seth
case class Name(
  salutation: String,       with first name set to
  first: String,            “Scott”
  last: String)

case class Phone(
  digits: String)

val seth = Contact(
  Name("Mr.", "Seth", "Avett"), Phone("555-5555"))
Lens: Problem Statement
val seth = Contact(
  Name("Mr.", "Seth", "Avett"),
  Phone("555-5555"))

val scott = seth.copy(
  name = seth.name.copy(first = "Scott"))
Lens: Problem Statement
val seth = Contact(
  Name("Mr.", "Seth", "Avett"),
  Phone("555-5555"))

val scott = seth.copy(
  name = seth.name.copy(first = "Scott"))


Doesn’t scale - each layer in record structure results
in another layer of copies and duplication
Lens

• Given a record type and a field, a lens provides the
  ability to focus on the specified field, which allows
  accessing the field value and setting the field value
  (immutably)
Lens

• Given a record type and a field, a 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

case class Contact(
                              Record Type   Field Type
  name: Name,
  phone: Phone)

val contactNameLens = Lens.lensu[Contact, Name](
  (c, n) => c.copy(name = n), _.name)
       Setter                 Getter
val contactPhoneLens = Lens.lensu[Contact, Phone](
  (c, p) => c.copy(phone = p), _.phone)
       Setter                Getter
Lens
                       •Case class lenses usually use copy in
                       setter

case class Contact(
  name: Name,
  phone: Phone)

val contactNameLens = Lens.lensu[Contact, Name](
  (c, n) => c.copy(name = n), _.name)
       Setter                   Getter
val contactPhoneLens = Lens.lensu[Contact, Phone](
  (c, p) => c.copy(phone = p), _.phone)
       Setter                   Getter
Lens
                       •Case class lenses usually use copy in
                       setter

case class Contact(    •Case class lenses are purely mechanical to
  name: Name,          author (there’s even a compiler plugin that
  phone: Phone)        does it!)

val contactNameLens = Lens.lensu[Contact, Name](
  (c, n) => c.copy(name = n), _.name)
       Setter                   Getter
val contactPhoneLens = Lens.lensu[Contact, Phone](
  (c, p) => c.copy(phone = p), _.phone)
       Setter                   Getter
Lens
case class Name(
  salutation: String,
  first: String,
  last: String)

val nameSalutationLens = Lens.lensu[Name, String](
  (n, s) => n.copy(salutation = s), _.salutation)

val nameFirstLens = Lens.lensu[Name, String](
  (n, f) => n.copy(first = f), _.first)

val nameLastLens = Lens.lensu[Name, String](
  (n, l) => n.copy(last = l), _.last)
Lens


case class Phone(
  digits: String)

val phoneDigitsLens = Lens.lensu[Phone, String](
  (p, d) => p.copy(digits = d), _.digits)
Lens
                    Lenses compose!!
val contactFirstNameLens =
  contactNameLens >=> nameFirstLens
 Composes 2 lenses in to a Contact to First Name lens via andThen
Lens
                    Lenses compose!!
val contactFirstNameLens =
  contactNameLens >=> nameFirstLens
 Composes 2 lenses in to a Contact to First Name lens via andThen

val seth = Contact(
  Name("Mr.", "Seth", "Avett"), Phone("555-5555"))
Lens
                    Lenses compose!!
val contactFirstNameLens =
  contactNameLens >=> nameFirstLens
 Composes 2 lenses in to a Contact to First Name lens via andThen

val seth = Contact(
  Name("Mr.", "Seth", "Avett"), Phone("555-5555"))

contactFirstNameLens.get(seth)
                            “Seth”
Lens
                    Lenses compose!!
val contactFirstNameLens =
  contactNameLens >=> nameFirstLens
 Composes 2 lenses in to a Contact to First Name lens via andThen

val seth = Contact(
  Name("Mr.", "Seth", "Avett"), Phone("555-5555"))

contactFirstNameLens.get(seth)
                            “Seth”

contactFirstNameLens.set(seth, "Scott")
       Contact(Name(Mr.,Scott,Avett),Phone(555-5555))
Future Topics
• Zipper
• Reader             • Arrow
• Writer             • Kleisli
• State              • Category
• Monad              • Iteratees
  Transformers


           ...and much more!
Questions?



Photo Credit: http://www.flickr.com/photos/yannconz/2795462449

Más contenido relacionado

La actualidad más candente

The Death of Final Tagless
The Death of Final TaglessThe Death of Final Tagless
The Death of Final TaglessJohn De Goes
 
Scala for Java Programmers
Scala for Java ProgrammersScala for Java Programmers
Scala for Java ProgrammersEric Pederson
 
Kotlin Basics - Apalon Kotlin Sprint Part 2
Kotlin Basics - Apalon Kotlin Sprint Part 2Kotlin Basics - Apalon Kotlin Sprint Part 2
Kotlin Basics - Apalon Kotlin Sprint Part 2Kirill Rozov
 
Monad Transformers In The Wild
Monad Transformers In The WildMonad Transformers In The Wild
Monad Transformers In The WildStackMob Inc
 
The Design of the Scalaz 8 Effect System
The Design of the Scalaz 8 Effect SystemThe Design of the Scalaz 8 Effect System
The Design of the Scalaz 8 Effect SystemJohn De Goes
 
Quark: A Purely-Functional Scala DSL for Data Processing & Analytics
Quark: A Purely-Functional Scala DSL for Data Processing & AnalyticsQuark: A Purely-Functional Scala DSL for Data Processing & Analytics
Quark: A Purely-Functional Scala DSL for Data Processing & AnalyticsJohn De Goes
 
Writing DSL with Applicative Functors
Writing DSL with Applicative FunctorsWriting DSL with Applicative Functors
Writing DSL with Applicative FunctorsDavid Galichet
 
Refactoring Functional Type Classes
Refactoring Functional Type ClassesRefactoring Functional Type Classes
Refactoring Functional Type ClassesJohn De Goes
 
Intro to Functional Programming in Scala
Intro to Functional Programming in ScalaIntro to Functional Programming in Scala
Intro to Functional Programming in ScalaShai Yallin
 
Mining Functional Patterns
Mining Functional PatternsMining Functional Patterns
Mining Functional PatternsDebasish Ghosh
 
Principled Error Handling with FP
Principled Error Handling with FPPrincipled Error Handling with FP
Principled Error Handling with FPLuka Jacobowitz
 
Learn JavaScript by modeling Rubik Cube
Learn JavaScript by modeling Rubik CubeLearn JavaScript by modeling Rubik Cube
Learn JavaScript by modeling Rubik CubeManoj Kumar
 
Testing in the World of Functional Programming
Testing in the World of Functional ProgrammingTesting in the World of Functional Programming
Testing in the World of Functional ProgrammingLuka Jacobowitz
 
Post-Free: Life After Free Monads
Post-Free: Life After Free MonadsPost-Free: Life After Free Monads
Post-Free: Life After Free MonadsJohn De Goes
 
Pragmatic Real-World Scala (short version)
Pragmatic Real-World Scala (short version)Pragmatic Real-World Scala (short version)
Pragmatic Real-World Scala (short version)Jonas Bonér
 
A Prelude of Purity: Scaling Back ZIO
A Prelude of Purity: Scaling Back ZIOA Prelude of Purity: Scaling Back ZIO
A Prelude of Purity: Scaling Back ZIOJorge Vásquez
 
Blazing Fast, Pure Effects without Monads — LambdaConf 2018
Blazing Fast, Pure Effects without Monads — LambdaConf 2018Blazing Fast, Pure Effects without Monads — LambdaConf 2018
Blazing Fast, Pure Effects without Monads — LambdaConf 2018John De Goes
 

La actualidad más candente (20)

The Death of Final Tagless
The Death of Final TaglessThe Death of Final Tagless
The Death of Final Tagless
 
Scala for Java Programmers
Scala for Java ProgrammersScala for Java Programmers
Scala for Java Programmers
 
Kotlin Basics - Apalon Kotlin Sprint Part 2
Kotlin Basics - Apalon Kotlin Sprint Part 2Kotlin Basics - Apalon Kotlin Sprint Part 2
Kotlin Basics - Apalon Kotlin Sprint Part 2
 
Monad Transformers In The Wild
Monad Transformers In The WildMonad Transformers In The Wild
Monad Transformers In The Wild
 
Joy of scala
Joy of scalaJoy of scala
Joy of scala
 
The Design of the Scalaz 8 Effect System
The Design of the Scalaz 8 Effect SystemThe Design of the Scalaz 8 Effect System
The Design of the Scalaz 8 Effect System
 
Quark: A Purely-Functional Scala DSL for Data Processing & Analytics
Quark: A Purely-Functional Scala DSL for Data Processing & AnalyticsQuark: A Purely-Functional Scala DSL for Data Processing & Analytics
Quark: A Purely-Functional Scala DSL for Data Processing & Analytics
 
Writing DSL with Applicative Functors
Writing DSL with Applicative FunctorsWriting DSL with Applicative Functors
Writing DSL with Applicative Functors
 
Refactoring Functional Type Classes
Refactoring Functional Type ClassesRefactoring Functional Type Classes
Refactoring Functional Type Classes
 
Intro to Functional Programming in Scala
Intro to Functional Programming in ScalaIntro to Functional Programming in Scala
Intro to Functional Programming in Scala
 
ppopoff
ppopoffppopoff
ppopoff
 
SDC - Einführung in Scala
SDC - Einführung in ScalaSDC - Einführung in Scala
SDC - Einführung in Scala
 
Mining Functional Patterns
Mining Functional PatternsMining Functional Patterns
Mining Functional Patterns
 
Principled Error Handling with FP
Principled Error Handling with FPPrincipled Error Handling with FP
Principled Error Handling with FP
 
Learn JavaScript by modeling Rubik Cube
Learn JavaScript by modeling Rubik CubeLearn JavaScript by modeling Rubik Cube
Learn JavaScript by modeling Rubik Cube
 
Testing in the World of Functional Programming
Testing in the World of Functional ProgrammingTesting in the World of Functional Programming
Testing in the World of Functional Programming
 
Post-Free: Life After Free Monads
Post-Free: Life After Free MonadsPost-Free: Life After Free Monads
Post-Free: Life After Free Monads
 
Pragmatic Real-World Scala (short version)
Pragmatic Real-World Scala (short version)Pragmatic Real-World Scala (short version)
Pragmatic Real-World Scala (short version)
 
A Prelude of Purity: Scaling Back ZIO
A Prelude of Purity: Scaling Back ZIOA Prelude of Purity: Scaling Back ZIO
A Prelude of Purity: Scaling Back ZIO
 
Blazing Fast, Pure Effects without Monads — LambdaConf 2018
Blazing Fast, Pure Effects without Monads — LambdaConf 2018Blazing Fast, Pure Effects without Monads — LambdaConf 2018
Blazing Fast, Pure Effects without Monads — LambdaConf 2018
 

Destacado

Scalaz By Example (An IO Taster) -- PDXScala Meetup Jan 2014
Scalaz By Example (An IO Taster) -- PDXScala Meetup Jan 2014Scalaz By Example (An IO Taster) -- PDXScala Meetup Jan 2014
Scalaz By Example (An IO Taster) -- PDXScala Meetup Jan 2014Susan Potter
 
Railway Oriented Programming
Railway Oriented ProgrammingRailway Oriented Programming
Railway Oriented ProgrammingScott Wlaschin
 
A Scala Corrections Library
A Scala Corrections LibraryA Scala Corrections Library
A Scala Corrections LibraryPaul Phillips
 
The state of sbt 0.13, sbt server, and sbt 1.0 (ScalaSphere ver)
The state of sbt 0.13, sbt server, and sbt 1.0 (ScalaSphere ver)The state of sbt 0.13, sbt server, and sbt 1.0 (ScalaSphere ver)
The state of sbt 0.13, sbt server, and sbt 1.0 (ScalaSphere ver)Eugene Yokota
 
Age is not an int
Age is not an intAge is not an int
Age is not an intoxbow_lakes
 
Practically Functional
Practically FunctionalPractically Functional
Practically Functionaldjspiewak
 
Optics with monocle - Modeling the part and the whole
Optics with monocle - Modeling the part and the wholeOptics with monocle - Modeling the part and the whole
Optics with monocle - Modeling the part and the wholeIlan Godik
 
Building financial systems in scala
Building financial systems in scalaBuilding financial systems in scala
Building financial systems in scalaoxbow_lakes
 
Scala lens: An introduction
Scala lens: An introductionScala lens: An introduction
Scala lens: An introductionKnoldus Inc.
 
Introduction to ScalaZ
Introduction to ScalaZIntroduction to ScalaZ
Introduction to ScalaZKnoldus Inc.
 
Purely Functional Data Structures in Scala
Purely Functional Data Structures in ScalaPurely Functional Data Structures in Scala
Purely Functional Data Structures in ScalaVladimir Kostyukov
 
Monadic Programmingのススメ - Functional Reactive Programmingへのアプローチ
Monadic Programmingのススメ - Functional Reactive ProgrammingへのアプローチMonadic Programmingのススメ - Functional Reactive Programmingへのアプローチ
Monadic Programmingのススメ - Functional Reactive ProgrammingへのアプローチTomoharu ASAMI
 
Advanced Functional Programming in Scala
Advanced Functional Programming in ScalaAdvanced Functional Programming in Scala
Advanced Functional Programming in ScalaPatrick Nicolas
 
A dive into akka streams: from the basics to a real-world scenario
A dive into akka streams: from the basics to a real-world scenarioA dive into akka streams: from the basics to a real-world scenario
A dive into akka streams: from the basics to a real-world scenarioGioia Ballin
 
Introduction to Laws
Introduction to LawsIntroduction to Laws
Introduction to Lawsnkpart
 
Grokking Monads in Scala
Grokking Monads in ScalaGrokking Monads in Scala
Grokking Monads in ScalaTim Dalton
 
λ | Lenses
λ | Lensesλ | Lenses
λ | LensesOpen-IT
 
Bulletproof Jobs: Patterns for Large-Scale Spark Processing: Spark Summit Eas...
Bulletproof Jobs: Patterns for Large-Scale Spark Processing: Spark Summit Eas...Bulletproof Jobs: Patterns for Large-Scale Spark Processing: Spark Summit Eas...
Bulletproof Jobs: Patterns for Large-Scale Spark Processing: Spark Summit Eas...Spark Summit
 
Demystifying Shapeless
Demystifying Shapeless Demystifying Shapeless
Demystifying Shapeless Jared Roesch
 

Destacado (19)

Scalaz By Example (An IO Taster) -- PDXScala Meetup Jan 2014
Scalaz By Example (An IO Taster) -- PDXScala Meetup Jan 2014Scalaz By Example (An IO Taster) -- PDXScala Meetup Jan 2014
Scalaz By Example (An IO Taster) -- PDXScala Meetup Jan 2014
 
Railway Oriented Programming
Railway Oriented ProgrammingRailway Oriented Programming
Railway Oriented Programming
 
A Scala Corrections Library
A Scala Corrections LibraryA Scala Corrections Library
A Scala Corrections Library
 
The state of sbt 0.13, sbt server, and sbt 1.0 (ScalaSphere ver)
The state of sbt 0.13, sbt server, and sbt 1.0 (ScalaSphere ver)The state of sbt 0.13, sbt server, and sbt 1.0 (ScalaSphere ver)
The state of sbt 0.13, sbt server, and sbt 1.0 (ScalaSphere ver)
 
Age is not an int
Age is not an intAge is not an int
Age is not an int
 
Practically Functional
Practically FunctionalPractically Functional
Practically Functional
 
Optics with monocle - Modeling the part and the whole
Optics with monocle - Modeling the part and the wholeOptics with monocle - Modeling the part and the whole
Optics with monocle - Modeling the part and the whole
 
Building financial systems in scala
Building financial systems in scalaBuilding financial systems in scala
Building financial systems in scala
 
Scala lens: An introduction
Scala lens: An introductionScala lens: An introduction
Scala lens: An introduction
 
Introduction to ScalaZ
Introduction to ScalaZIntroduction to ScalaZ
Introduction to ScalaZ
 
Purely Functional Data Structures in Scala
Purely Functional Data Structures in ScalaPurely Functional Data Structures in Scala
Purely Functional Data Structures in Scala
 
Monadic Programmingのススメ - Functional Reactive Programmingへのアプローチ
Monadic Programmingのススメ - Functional Reactive ProgrammingへのアプローチMonadic Programmingのススメ - Functional Reactive Programmingへのアプローチ
Monadic Programmingのススメ - Functional Reactive Programmingへのアプローチ
 
Advanced Functional Programming in Scala
Advanced Functional Programming in ScalaAdvanced Functional Programming in Scala
Advanced Functional Programming in Scala
 
A dive into akka streams: from the basics to a real-world scenario
A dive into akka streams: from the basics to a real-world scenarioA dive into akka streams: from the basics to a real-world scenario
A dive into akka streams: from the basics to a real-world scenario
 
Introduction to Laws
Introduction to LawsIntroduction to Laws
Introduction to Laws
 
Grokking Monads in Scala
Grokking Monads in ScalaGrokking Monads in Scala
Grokking Monads in Scala
 
λ | Lenses
λ | Lensesλ | Lenses
λ | Lenses
 
Bulletproof Jobs: Patterns for Large-Scale Spark Processing: Spark Summit Eas...
Bulletproof Jobs: Patterns for Large-Scale Spark Processing: Spark Summit Eas...Bulletproof Jobs: Patterns for Large-Scale Spark Processing: Spark Summit Eas...
Bulletproof Jobs: Patterns for Large-Scale Spark Processing: Spark Summit Eas...
 
Demystifying Shapeless
Demystifying Shapeless Demystifying Shapeless
Demystifying Shapeless
 

Similar a Scalaz: Functional Programming with Options, Monoids and Functors

Monads and friends demystified
Monads and friends demystifiedMonads and friends demystified
Monads and friends demystifiedAlessandro Lacava
 
mat lab introduction and basics to learn
mat lab introduction and basics to learnmat lab introduction and basics to learn
mat lab introduction and basics to learnpavan373
 
Denis Lebedev, Swift
Denis  Lebedev, SwiftDenis  Lebedev, Swift
Denis Lebedev, SwiftYandex
 
Monadologie
MonadologieMonadologie
Monadologieleague
 
Power of functions in a typed world
Power of functions in a typed worldPower of functions in a typed world
Power of functions in a typed worldDebasish Ghosh
 
Scala: Functioneel programmeren in een object georiënteerde wereld
Scala: Functioneel programmeren in een object georiënteerde wereldScala: Functioneel programmeren in een object georiënteerde wereld
Scala: Functioneel programmeren in een object georiënteerde wereldWerner Hofstra
 
Coscup2021 - useful abstractions at rust and it's practical usage
Coscup2021 - useful abstractions at rust and it's practical usageCoscup2021 - useful abstractions at rust and it's practical usage
Coscup2021 - useful abstractions at rust and it's practical usageWayne Tsai
 
Advance Scala - Oleg Mürk
Advance Scala - Oleg MürkAdvance Scala - Oleg Mürk
Advance Scala - Oleg MürkPlanet OS
 
(How) can we benefit from adopting scala?
(How) can we benefit from adopting scala?(How) can we benefit from adopting scala?
(How) can we benefit from adopting scala?Tomasz Wrobel
 
Fun with Lambdas: C++14 Style (part 2)
Fun with Lambdas: C++14 Style (part 2)Fun with Lambdas: C++14 Style (part 2)
Fun with Lambdas: C++14 Style (part 2)Sumant Tambe
 
Monads and Monoids by Oleksiy Dyagilev
Monads and Monoids by Oleksiy DyagilevMonads and Monoids by Oleksiy Dyagilev
Monads and Monoids by Oleksiy DyagilevJavaDayUA
 
An excuse to Try, Either, folding, and Future. sequence
An excuse to Try, Either, folding, and Future. sequenceAn excuse to Try, Either, folding, and Future. sequence
An excuse to Try, Either, folding, and Future. sequenceGermán Ferrari
 
An overview of Python 2.7
An overview of Python 2.7An overview of Python 2.7
An overview of Python 2.7decoupled
 
Monoids - Part 1 - with examples using Scalaz and Cats
Monoids - Part 1 - with examples using Scalaz and CatsMonoids - Part 1 - with examples using Scalaz and Cats
Monoids - Part 1 - with examples using Scalaz and CatsPhilip Schwarz
 
Types by Adform Research
Types by Adform ResearchTypes by Adform Research
Types by Adform ResearchVasil Remeniuk
 
Type Classes in Scala and Haskell
Type Classes in Scala and HaskellType Classes in Scala and Haskell
Type Classes in Scala and HaskellHermann Hueck
 

Similar a Scalaz: Functional Programming with Options, Monoids and Functors (20)

Monads and friends demystified
Monads and friends demystifiedMonads and friends demystified
Monads and friends demystified
 
mat lab introduction and basics to learn
mat lab introduction and basics to learnmat lab introduction and basics to learn
mat lab introduction and basics to learn
 
Denis Lebedev, Swift
Denis  Lebedev, SwiftDenis  Lebedev, Swift
Denis Lebedev, Swift
 
Monadologie
MonadologieMonadologie
Monadologie
 
Power of functions in a typed world
Power of functions in a typed worldPower of functions in a typed world
Power of functions in a typed world
 
Scala: Functioneel programmeren in een object georiënteerde wereld
Scala: Functioneel programmeren in een object georiënteerde wereldScala: Functioneel programmeren in een object georiënteerde wereld
Scala: Functioneel programmeren in een object georiënteerde wereld
 
Coscup2021 - useful abstractions at rust and it's practical usage
Coscup2021 - useful abstractions at rust and it's practical usageCoscup2021 - useful abstractions at rust and it's practical usage
Coscup2021 - useful abstractions at rust and it's practical usage
 
Advance Scala - Oleg Mürk
Advance Scala - Oleg MürkAdvance Scala - Oleg Mürk
Advance Scala - Oleg Mürk
 
(How) can we benefit from adopting scala?
(How) can we benefit from adopting scala?(How) can we benefit from adopting scala?
(How) can we benefit from adopting scala?
 
Mbd2
Mbd2Mbd2
Mbd2
 
Fun with Lambdas: C++14 Style (part 2)
Fun with Lambdas: C++14 Style (part 2)Fun with Lambdas: C++14 Style (part 2)
Fun with Lambdas: C++14 Style (part 2)
 
Monads and Monoids by Oleksiy Dyagilev
Monads and Monoids by Oleksiy DyagilevMonads and Monoids by Oleksiy Dyagilev
Monads and Monoids by Oleksiy Dyagilev
 
An excuse to Try, Either, folding, and Future. sequence
An excuse to Try, Either, folding, and Future. sequenceAn excuse to Try, Either, folding, and Future. sequence
An excuse to Try, Either, folding, and Future. sequence
 
An introduction to scala
An introduction to scalaAn introduction to scala
An introduction to scala
 
An overview of Python 2.7
An overview of Python 2.7An overview of Python 2.7
An overview of Python 2.7
 
A tour of Python
A tour of PythonA tour of Python
A tour of Python
 
Monoids - Part 1 - with examples using Scalaz and Cats
Monoids - Part 1 - with examples using Scalaz and CatsMonoids - Part 1 - with examples using Scalaz and Cats
Monoids - Part 1 - with examples using Scalaz and Cats
 
Types by Adform Research
Types by Adform ResearchTypes by Adform Research
Types by Adform Research
 
Scala jargon cheatsheet
Scala jargon cheatsheetScala jargon cheatsheet
Scala jargon cheatsheet
 
Type Classes in Scala and Haskell
Type Classes in Scala and HaskellType Classes in Scala and Haskell
Type Classes in Scala and Haskell
 

Último

Pigging Solutions Piggable Sweeping Elbows
Pigging Solutions Piggable Sweeping ElbowsPigging Solutions Piggable Sweeping Elbows
Pigging Solutions Piggable Sweeping ElbowsPigging Solutions
 
Understanding the Laravel MVC Architecture
Understanding the Laravel MVC ArchitectureUnderstanding the Laravel MVC Architecture
Understanding the Laravel MVC ArchitecturePixlogix Infotech
 
Handwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsHandwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsMaria Levchenko
 
08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking Men08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking MenDelhi Call girls
 
The Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptxThe Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptxMalak Abu Hammad
 
[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdfhans926745
 
Transforming Data Streams with Kafka Connect: An Introduction to Single Messa...
Transforming Data Streams with Kafka Connect: An Introduction to Single Messa...Transforming Data Streams with Kafka Connect: An Introduction to Single Messa...
Transforming Data Streams with Kafka Connect: An Introduction to Single Messa...HostedbyConfluent
 
Pigging Solutions in Pet Food Manufacturing
Pigging Solutions in Pet Food ManufacturingPigging Solutions in Pet Food Manufacturing
Pigging Solutions in Pet Food ManufacturingPigging Solutions
 
How to Remove Document Management Hurdles with X-Docs?
How to Remove Document Management Hurdles with X-Docs?How to Remove Document Management Hurdles with X-Docs?
How to Remove Document Management Hurdles with X-Docs?XfilesPro
 
AI as an Interface for Commercial Buildings
AI as an Interface for Commercial BuildingsAI as an Interface for Commercial Buildings
AI as an Interface for Commercial BuildingsMemoori
 
Slack Application Development 101 Slides
Slack Application Development 101 SlidesSlack Application Development 101 Slides
Slack Application Development 101 Slidespraypatel2
 
Transcript: #StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
Transcript: #StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024Transcript: #StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
Transcript: #StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024BookNet Canada
 
IAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsIAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsEnterprise Knowledge
 
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024BookNet Canada
 
08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking MenDelhi Call girls
 
Presentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreterPresentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreternaman860154
 
GenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationGenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationMichael W. Hawkins
 
Breaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountBreaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountPuma Security, LLC
 
Install Stable Diffusion in windows machine
Install Stable Diffusion in windows machineInstall Stable Diffusion in windows machine
Install Stable Diffusion in windows machinePadma Pradeep
 
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 3652toLead Limited
 

Último (20)

Pigging Solutions Piggable Sweeping Elbows
Pigging Solutions Piggable Sweeping ElbowsPigging Solutions Piggable Sweeping Elbows
Pigging Solutions Piggable Sweeping Elbows
 
Understanding the Laravel MVC Architecture
Understanding the Laravel MVC ArchitectureUnderstanding the Laravel MVC Architecture
Understanding the Laravel MVC Architecture
 
Handwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsHandwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed texts
 
08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking Men08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking Men
 
The Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptxThe Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptx
 
[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf
 
Transforming Data Streams with Kafka Connect: An Introduction to Single Messa...
Transforming Data Streams with Kafka Connect: An Introduction to Single Messa...Transforming Data Streams with Kafka Connect: An Introduction to Single Messa...
Transforming Data Streams with Kafka Connect: An Introduction to Single Messa...
 
Pigging Solutions in Pet Food Manufacturing
Pigging Solutions in Pet Food ManufacturingPigging Solutions in Pet Food Manufacturing
Pigging Solutions in Pet Food Manufacturing
 
How to Remove Document Management Hurdles with X-Docs?
How to Remove Document Management Hurdles with X-Docs?How to Remove Document Management Hurdles with X-Docs?
How to Remove Document Management Hurdles with X-Docs?
 
AI as an Interface for Commercial Buildings
AI as an Interface for Commercial BuildingsAI as an Interface for Commercial Buildings
AI as an Interface for Commercial Buildings
 
Slack Application Development 101 Slides
Slack Application Development 101 SlidesSlack Application Development 101 Slides
Slack Application Development 101 Slides
 
Transcript: #StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
Transcript: #StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024Transcript: #StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
Transcript: #StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
 
IAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsIAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI Solutions
 
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
 
08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men
 
Presentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreterPresentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreter
 
GenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationGenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day Presentation
 
Breaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountBreaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path Mount
 
Install Stable Diffusion in windows machine
Install Stable Diffusion in windows machineInstall Stable Diffusion in windows machine
Install Stable Diffusion in windows machine
 
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
 

Scalaz: Functional Programming with Options, Monoids and Functors

  • 1. Scalaz There’s an applicative in my functor! Photo Credit: http://www.flickr.com/photos/yannconz/2796312310
  • 2. Agenda • Option • Monoid • Applicative • Validation • Lens
  • 3. Options • Option functions & typeclass instances • Option syntax extensions • Using Option with other parts of Scalaz
  • 4. Constructing Options Some(42) Some[Int] None None
  • 5. Constructing Options Some(42) Some[Int] None None import scalaz.std.option._ some(42) Option[Int] none[Int] Option[Int]
  • 6. Constructing Options Some(42) Some[Int] None None Imports functions & typeclass instances for option import scalaz.std.option._ some(42) Option[Int] none[Int] Option[Int]
  • 7. Constructing Options val os = List(Some(42), None, Some(20)) os.foldLeft(None) { (acc, o) => acc orElse o }
  • 8. Constructing Options val os = List(Some(42), None, Some(20)) os.foldLeft(None) { (acc, o) => acc orElse o } error: type mismatch; found : Option[Int] required: None.type os.foldLeft(None) { (acc, o) => acc orElse o } ^
  • 9. Constructing Options val os = List(Some(42), None, Some(20)) os.foldLeft(None) { (acc, o) => acc orElse o } error: type mismatch; found : Option[Int] required: None.type os.foldLeft(None) { (acc, o) => acc orElse o } ^ os.foldLeft(None: Option[Int]) { (acc, o) => acc orElse o } Some(42)
  • 10. Constructing Options val os = List(Some(42), None, Some(20)) os.foldLeft(None) { (acc, o) => acc orElse o } error: type mismatch; found : Option[Int] required: None.type os.foldLeft(None) { (acc, o) => acc orElse o } ^ os.foldLeft(None: Option[Int]) { (acc, o) => acc orElse o } Some(42) os.foldLeft(none[Int]) { (acc, o) => acc orElse o } Some(42)
  • 11. Option conditional import scalaz.syntax.std.option._ def xget(opt: Option[Int]) = opt | Int.MaxValue xget(Some(42)) xget(None)
  • 12. Option conditional Imports syntax extensions for option import scalaz.syntax.std.option._ def xget(opt: Option[Int]) = opt | Int.MaxValue xget(Some(42)) xget(None)
  • 13. Option conditional Alias for getOrElse import scalaz.syntax.std.option._ def xget(opt: Option[Int]) = opt | Int.MaxValue xget(Some(42)) xget(None)
  • 14. Option conditional import scalaz.syntax.std.option._ def xget(opt: Option[Int]) = opt | Int.MaxValue xget(Some(42)) 42 214748364 xget(None) 7
  • 15. Option unary ~ import scalaz.std.anyVal._ import scalaz.std.option._ import scalaz.syntax.std.option._ def zget(opt: Option[Int]) = ~opt zget(Some(42)) zget(None)
  • 16. Option unary ~ Imports functions & typeclass instances for int, float, etc. import scalaz.std.anyVal._ import scalaz.std.option._ import scalaz.syntax.std.option._ def zget(opt: Option[Int]) = ~opt zget(Some(42)) zget(None)
  • 17. Option unary ~ Alias for getOrElse(zero) import scalaz.std.anyVal._ import scalaz.std.option._ import scalaz.syntax.std.option._ def zget(opt: Option[Int]) = ~opt zget(Some(42)) zget(None)
  • 18. Option unary ~ Alias for getOrElse(zero) import scalaz.std.anyVal._ import scalaz.std.option._ import scalaz.syntax.std.option._ def zget(opt: Option[Int]) = ~opt zget(Some(42)) 42 zget(None) 0
  • 19. Option unary ~ Alias for getOrElse(zero) import scalaz.std.anyVal._ import scalaz.std.option._ import scalaz.syntax.std.option._ def zget(opt: Option[Int]) = ~opt zget(Some(42)) 42 zget(None) 0 Where does zero come from?
  • 20. Option unary ~ import scalaz.Monoid import scalaz.std.string._ import scalaz.std.list._ def mzget[A : Monoid](opt: Option[A]) = ~opt mzget(none[Int]) 0 mzget(none[String]) “” mzget(none[List[Int]]) List()
  • 21. Aside: Context Bounds def mzget[A : Monoid](opt: Option[A]) = ~opt
  • 22. Aside: Context Bounds def mzget[A : Monoid](opt: Option[A]) = ~opt • Monoid is a context bound for type A
  • 23. Aside: Context Bounds def mzget[A : Monoid](opt: Option[A]) = ~opt • Monoid is a context bound for type A • Means there must be an implicit value of type Monoid[A] in implicit scope
  • 24. Aside: Context Bounds def mzget[A : Monoid](opt: Option[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
  • 25. Aside: Context Bounds def mzget[A : Monoid](opt: Option[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 other[A multiple bounds: def supports : Monoid : Functor] = ...
  • 26. Option err def knowBetter[A](opt: Option[A]) = opt err "You promised!" knowBetter(some(42)) knowBetter(none)
  • 27. Option err Alias for getOrElse(sys.err(msg)) def knowBetter[A](opt: Option[A]) = opt err "You promised!" knowBetter(some(42)) 42 knowBetter(none) throws RuntimException(“You promised!”) Good alternative to opt.get when you know it’s defined!
  • 28. Option fold/cata import java.net.InetAddress def ipAddress(opt: Option[InetAddress]) = opt.fold(_.getHostAddress, "0.0.0.0") ipAddress(Some(InetAddress.getLocalHost)) ipAddress(None)
  • 29. Option fold/cata Replacement for matching on Some/None import java.net.InetAddress def ipAddress(opt: Option[InetAddress]) = opt.fold(_.getHostAddress, "0.0.0.0") ipAddress(Some(InetAddress.getLocalHost)) 10.0.1.1 ipAddress(None) 2 0.0.0.0
  • 30. Option ifNone var cnt = 0 some(42) ifNone { cnt += 1 } none ifNone { cnt += 1 } println(cnt)
  • 31. Concatenate Given a list of options, how do you sum them? List(some(42), none, some(51)).sum error: could not find implicit value for parameter num: Numeric[Option[Int]]
  • 32. Concatenate Given a list of options, how do you sum 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
  • 33. Sequence Given a list of options, how do you get option of list? List(some(42), none, some(51)).sequence None List(some(42), some(51)).sequence Some(List(42, 51))
  • 34. Semigroup & Monoid Review Not Scala syntax! • SemigroupA append: A A • Monoid extends Semigroup zero: A
  • 35. Syntax import scalaz.std.anyVal._ import scalaz.syntax.monoid._ 1 |+| 2 3 import scalaz.std.list._ List(1, 2) |+| List(3, 4) List(1, 2, 3, 4)
  • 36. Syntax import scalaz.std.map._ import scalaz.std.set._ val low = Map( 'odd -> Set(1, 3), 'even -> Set(2, 4)) val hi = Map( 'odd -> Set(5, 7), 'even -> Set(6, 8)) low |+| hi
  • 37. Syntax import scalaz.std.map._ import scalaz.std.set._ val low = Map( 'odd -> Set(1, 3), 'even -> Set(2, 4)) val hi = Map( 'odd -> Set(5, 7), 'even -> Set(6, 8)) low |+| hi Map(‘odd -> Set(1, 3, 5, 7), ‘even -> Set(2, 4, 6, 8))
  • 38. Option is Monoid • There’s a monoid of Option[A] if A is a Semigroup • zero = None • append = ???
  • 39. Option is Monoid implicit def optionMonoid[A: Semigroup]: Monoid[Option[A]] = new Monoid[Option[A]] { def append(f1: Option[A], f2: => Option[A]) = (f1, f2) match { case (Some(a1), Some(a2)) => Some(Semigroup[A].append(a1, a2)) case (Some(a1), None) => f1 case (None, Some(a2)) => f2 case (None, None) => None } def zero: Option[A] = None } From Scalaz Seven source https://github.com/scalaz/scalaz/blob/scalaz-seven/core/src/main/scala/scalaz/std/Option.scala
  • 40. Option is Monoid import scalaz.syntax.monoid._ some(20) |+| none |+| some(22) Some(42)
  • 41. Option alternative monoids • Can we find other monoids for Option? • Must implement zero and append • But remember the monoid laws: • Closure • Associativity • Identity See: http://en.wikipedia.org/wiki/Monoid
  • 42. Option alternative monoids • Keep everything the same as semigroup based monoid but focus on: case (Some(a1), Some(a2)) => • Left case (Some(a1), Some(a2)) => f1 • Right case (Some(a1), Some(a2)) => f2
  • 43. Option alternative monoids some(20).first |+| none.first |+| some(22).first Some(20) some(20).last |+| none.last |+| some(22).last Some(22)
  • 44. Functor & Monad Review Not Scala syntax! • Functor map: F[A] (A B) F[B] • Monad extendsM[A] point: A Functor flatMap: M[A] (A M[B]) M[B]
  • 45. Functor & Monad Review Not Scala syntax! • Functor map: F[A] (A B) F[B] Option[Int] (Int String) Option[String] • Monad extendsM[A] point: A Functor flatMap: M[A] (A M[B]) M[B]
  • 46. Functor & Monad Review Not Scala syntax! • Functor map: F[A] (A B) F[B] Option[Int] (Int String) Option[String] • Monad extendsM[A] point: A Functor flatMap: M[A] (A M[B]) M[B]
  • 47. Functor & Monad Review Not Scala syntax! • Functor map: F[A] (A B) F[B] Option[Int] (Int String) Option[String] • Monad extendsM[A] point: A Functor flatMap: M[A] (A M[B]) M[B] String Option[String] Option[String] (String Option[Int]) Option[Int]
  • 48. What’s this? • ??? extends Functor point: A F[A] ???: F[A] F[A B] F[B]
  • 49. What’s this? • ??? extends Functor point: A F[A] ???: 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.
  • 50. What’s this? • ??? extends Functor point: A F[A] ???: 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
  • 51. What’s this? • ??? extends Functor point: A F[A] ???: 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
  • 52. Applicative • Applicative extends Functor point: A F[A] ap: F[A] F[A B] F[B] Summarized from Scalaz Seven source https://github.com/scalaz/scalaz/blob/scalaz-seven/core/src/main/scala/scalaz/Pointed.scala https://github.com/scalaz/scalaz/blob/scalaz-seven/core/src/main/scala/scalaz/Applicative.scala
  • 53. Applicative • Applicative extends Functor point: A F[A] ap: F[A] F[A B] F[B] • Or in proper Scala: trait Pointed[F[_]] extends Functor[F] { def point[A](a: => A): F[A] } trait Applicative[F[_]] extends Functor[F] with Pointed[F] { def ap[A,B](fa: => F[A])(f: => F[A => B]): F[B] } Summarized from Scalaz Seven source https://github.com/scalaz/scalaz/blob/scalaz-seven/core/src/main/scala/scalaz/Pointed.scala https://github.com/scalaz/scalaz/blob/scalaz-seven/core/src/main/scala/scalaz/Applicative.scala
  • 54. Option Is Applicative Let’s define an applicative instance for Option implicit val optionInstance = new Applicative[Option] { override def point[A](a: => A) = ??? override def ap[A, B]( fa: => Option[A])(f: => Option[A => B]) = ??? } Summarized from Scalaz Seven source https://github.com/scalaz/scalaz/blob/scalaz-seven/core/src/main/scala/scalaz/Option.scala
  • 55. Option Is Applicative How can we lift a value of A to Option[A]? implicit val optionInstance = new Applicative[Option] { override def point[A](a: => A) = ??? override def ap[A, B]( fa: => Option[A])(f: => Option[A => B]) = ??? } Summarized from Scalaz Seven source https://github.com/scalaz/scalaz/blob/scalaz-seven/core/src/main/scala/scalaz/Option.scala
  • 56. Option Is Applicative implicit val optionInstance = new Applicative[Option] { override def point[A](a: => A) = Some(a) override def ap[A, B]( fa: => Option[A])(f: => Option[A => B]) = ??? } Summarized from Scalaz Seven source https://github.com/scalaz/scalaz/blob/scalaz-seven/core/src/main/scala/scalaz/Option.scala
  • 57. Option Is Applicative How can we apply the function in Option[A=>B] to Option[A]? implicit val optionInstance = new Applicative[Option] { override def point[A](a: => A) = Some(a) override def ap[A, B]( fa: => Option[A])(f: => Option[A => B]) = ??? } Summarized from Scalaz Seven source https://github.com/scalaz/scalaz/blob/scalaz-seven/core/src/main/scala/scalaz/Option.scala
  • 58. Option Is Applicative implicit val optionInstance = new Applicative[Option] { override def point[A](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 } } Summarized from Scalaz Seven source https://github.com/scalaz/scalaz/blob/scalaz-seven/core/src/main/scala/scalaz/Option.scala
  • 59. Option Is Applicative implicit val optionInstance = new Applicative[Option] { override def point[A](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 } } What about map[A](f: A => B): Option[B]? Summarized from Scalaz Seven source https://github.com/scalaz/scalaz/blob/scalaz-seven/core/src/main/scala/scalaz/Option.scala
  • 60. Functor.map on Applicative Can we define map in terms of pointed and ap? trait Applicative[F[_]] extends Functor[F] with Pointed[F] { def ap[A,B](fa: => F[A])(f: => F[A => B]): F[B] override def map[A, B](fa: F[A])(f: A => B): F[B] = ??? } Summarized from Scalaz Seven source https://github.com/scalaz/scalaz/blob/scalaz-seven/core/src/main/scala/scalaz/Option.scala
  • 61. Functor.map on Applicative trait Applicative[F[_]] extends Functor[F] with Pointed[F] { def ap[A,B](fa: => F[A])(f: => F[A => B]): F[B] override def map[A, B](fa: F[A])(f: A => B): F[B] = ap(fa)(point(f)) } Summarized from Scalaz Seven source https://github.com/scalaz/scalaz/blob/scalaz-seven/core/src/main/scala/scalaz/Option.scala
  • 62. Applicative Usage import scalaz.std.option._ import scalaz.syntax.applicative._ val oa5: Option[Int => Int] = Some((_: Int) + 5) some(15) <*> oa5
  • 63. Applicative Usage import scalaz.std.option._ import scalaz.syntax.applicative._ val oa5: Option[Int => Int] = Some((_: Int) + 5) some(15) <*> oa5 Alias for ap
  • 64. Applicative Usage import scalaz.std.option._ import scalaz.syntax.applicative._ val oa5: Option[Int => Int] = Some((_: Int) + 5) some(15) <*> oa5 Some(20) Alias for ap
  • 65. Applicative Usage import scalaz.std.option._ import scalaz.syntax.applicative._ some(15).<**>(some(5)) { _ + _ } some(15).<***>(some(5), some(6)) { _ + _ + _ } some(15).<****>(some(5), some(6), some(7)) { _ + _ + _ + _ }
  • 66. Applicative Usage import scalaz.std.option._ import scalaz.syntax.applicative._ some(15).<**>(some(5)) { _ + _ } Some(20) some(15).<***>(some(5), some(6)) { _ + _ + _ } Some(26) some(15).<****>(some(5), some(6), some(7)) { Some(33) _ + _ + _ + _ }
  • 67. Applicative Builder Most common and convenient usage import scalaz.std.option._ import scalaz.syntax.applicative._ (some(15) |@| some(5)) apply { _ + _ } (some(15) |@| some(5) |@| some(6)) apply { _ + _ + _ } (some(15) |@| some(5)).tupled
  • 68. Applicative Builder Most common and convenient usage import scalaz.std.option._ import scalaz.syntax.applicative._ (some(15) |@| some(5)) apply { _ + _ } Some(20) (some(15) |@| some(5) |@| some(6)) apply { _ + _ + _ } (some(15) |@| some(5)).tupled Some(26) Some((15, 5))
  • 69. Applicative Builder Most common and convenient usage import scalaz.std.option._ import scalaz.syntax.applicative._ (some(15) |@| some(5)) apply { _ + _ } Some(20) (some(15) |@| some(5) |@| some(6)) apply { _ + _ + _ } (some(15) |@| some(5)).tupled Some(26) Some((15, 5)) Supports up to 12 arguments
  • 70. Applicative Builder import scalaz.std.option._ import scalaz.syntax.applicative._ case class Album(name: String, artist: String) (some("Wilco") ⊛ some("Sky Blue Sky")) apply Album.apply
  • 71. Applicative Builder Companion has an apply method import scalaz.std.option._ automatically created import scalaz.syntax.applicative._ case class Album(name: String, artist: String) (some("Wilco") ⊛ some("Sky Blue Sky")) apply Album.apply
  • 72. Applicative Builder Companion has an apply method import scalaz.std.option._ automatically created import scalaz.syntax.applicative._ case class Album(name: String, artist: String) (some("Wilco") ⊛ some("Sky Blue Sky")) apply Album.apply Alias for |@|
  • 73. Applicative Builder Companion has an apply method import scalaz.std.option._ automatically created import scalaz.syntax.applicative._ case class Album(name: String, artist: String) (some("Wilco") ⊛ some("Sky Blue Sky")) apply Album.apply Some(Album(Wilco, Sky Blue Sky)) Alias for |@|
  • 74. Why Applicatives? • Less restrictive than Monads, and thus, more general (powerful) • Composable http://blog.tmorris.net/monads-do-not-compose/ • Support parallel computation More on this point later...
  • 75. A word on typeclasses • So far we’ve seen Semigroup, Monoid, Functor, Pointed, Applicative, Monad
  • 76. A word on typeclasses • So far we’ve seen Semigroup, 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
  • 77. A word on typeclasses • So far we’ve seen Semigroup, 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
  • 78. Some Haskell Typeclasses Credit: Typeclassopedia http://www.haskell.org/haskellwiki/Typeclassopedia#Introduction
  • 79. Typeclass References • Haskell Typeclassopedia is a great reference for learning these http://www.haskell.org/haskellwiki/Typeclassopedia • Scala Typeclassopedia describes the big 3 (Functor, Applicative, Monad) http://typeclassopedia.bitbucket.org/
  • 80. Validation sealed trait Validation[+E, +A] { ... } final case class Success[E, A](a: A) extends Validation[E, A] final case class Failure[E, A](e: E) extends Validation[E, A]
  • 81. Validation • Represents either success or failure • On success, provides the successful value • On failure, provides the failure value • Sound familiar?
  • 83. Isomorphic to Either Validation Either Success ≅ Right Failure Left
  • 84. Isomorphic to Either Validation Either Success ≅ Right Failure Left Q: So why not just use Either?
  • 85. Isomorphic to Either Validation Either Success ≅ Right Failure Left 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
  • 86. Constructing Validations import scalaz.{Success, Failure} Success(42) Success[Nothing, Int] Failure("boom") Failure[String, Nothing]
  • 87. Constructing Validations import scalaz.{Success, Failure} Success(42) Success[Nothing, Int] Failure("boom") Failure[String, Nothing] import scalaz.Validation Validation.success(42) Validation[Nothing, Int] Validation.failure("boom") Validation[String, Nothing]
  • 88. Constructing Validations import scalaz.{Success, Failure} Success(42) Success[Nothing, Int] Failure("boom") Failure[String, Nothing] import scalaz.Validation Validation.success(42) Validation[Nothing, Int] Validation.failure("boom") Validation[String, Nothing] import scalaz.syntax.validation._ 42.success Validation[Nothing, Int] "boom".fail Validation[String, Nothing]
  • 89. Constructing Validations import scalaz.{Success, Failure} Success(42) Success[Nothing, Int] Failure("boom") Failure[String, Nothing] import scalaz.Validation Validation.success(42) Validation[Nothing, Int] Validation.failure("boom") Validation[String, Nothing] import scalaz.syntax.validation._ 42.success Validation[Nothing, Int] "boom".fail Validation[String, Nothing] 42.success[String] Validation[String, Int] "boom".fail[Int] Validation[String, Int]
  • 90. Option to Validation import scalaz.std.option._ import scalaz.syntax.std.option._ some(42).toSuccess("boom") none[Int].toSuccess("boom") some(42).toFailure("boom") none[Int].toFailure("boom")
  • 91. Option to Validation import scalaz.std.option._ import scalaz.syntax.std.option._ some(42).toSuccess("boom") Success(42) none[Int].toSuccess("boom") Failure(“boom”) some(42).toFailure("boom") none[Int].toFailure("boom")
  • 92. Option to Validation import scalaz.std.option._ import scalaz.syntax.std.option._ some(42).toSuccess("boom") Success(42) none[Int].toSuccess("boom") Failure(“boom”) some(42).toFailure("boom") Failure(42) none[Int].toFailure("boom") Success(“boom”)
  • 93. Either to Validation import scalaz.syntax.id._ import scalaz.Validation.fromEither fromEither(42.right) fromEither("boom".left)
  • 94. Either to Validation import scalaz.syntax.id._ import scalaz.Validation.fromEither fromEither(42.right) Success(42) fromEither("boom".left) Failure(“boom”)
  • 95. Throwing to Validation import scalaz.Validation.fromTryCatch fromTryCatch("42".toInt) fromTryCatch("notAnInt".toInt)
  • 96. Throwing to Validation import scalaz.Validation.fromTryCatch fromTryCatch("42".toInt) fromTryCatch("notAnInt".toInt) Success(42) Failure(java.lang.NumberFormatException: For input string: "notAnInt")
  • 97. Throwing to Validation import scalaz.Validation.fromTryCatch fromTryCatch("42".toInt) fromTryCatch("notAnInt".toInt) Success(42) Failure(java.lang.NumberFormatException: For input string: "notAnInt") fromTryCatch("notAnInt".toInt) .fail.map { _.getMessage }.validation
  • 98. Throwing to Validation import scalaz.Validation.fromTryCatch fromTryCatch("42".toInt) fromTryCatch("notAnInt".toInt) Success(42) Failure(java.lang.NumberFormatException: For input string: "notAnInt") fromTryCatch("notAnInt".toInt) .fail.map { _.getMessage }.validation Failure(For input string: "notAnInt")
  • 99. Mapping via Bifunctor import scalaz.syntax.bifunctor._ Bifunctor = functor of 2 arguments fromTryCatch("notAnInt".toInt). <-: { _.getMessage } <-: = Map left value
  • 100. Mapping via Bifunctor import scalaz.syntax.bifunctor._ Bifunctor = functor of 2 arguments fromTryCatch("notAnInt".toInt). <-: { _.getMessage } <-: = Map left value Failure(For input string: "notAnInt")
  • 101. Mapping via Bifunctor import scalaz.syntax.bifunctor._ Bifunctor = functor of 2 arguments fromTryCatch("notAnInt".toInt). <-: { _.getMessage } <-: = Map left value Failure(For input string: "notAnInt") fromTryCatch("notAnInt".toInt). bimap(_.getMessage, identity)
  • 102. Mapping via Bifunctor import scalaz.syntax.bifunctor._ Bifunctor = functor of 2 arguments fromTryCatch("notAnInt".toInt). <-: { _.getMessage } <-: = Map left value Failure(For input string: "notAnInt") fromTryCatch("notAnInt".toInt). bimap(_.getMessage, identity) Failure(For input string: "notAnInt")
  • 103. Validation is Monad def justMessage[S]( v: Validation[Throwable, S]): Validation[String, S] = v.<-: { _.getMessage } def extractId( metadata: Map[String, String]): Validation[String, UUID] = for { str <- metadata.get("id").toSuccess("No id property") id <- justMessage(fromTryCatch(UUID.fromString(str))) } yield id extractId(Map.empty) extractId(Map("id" -> "notUuid")) extractId(Map("id" -> UUID.randomUUID.toString))
  • 104. Validation is Monad def justMessage[S]( v: Validation[Throwable, S]): Validation[String, S] = v.<-: { _.getMessage } def extractId( metadata: Map[String, String]): Validation[String, UUID] = for { str <- metadata.get("id").toSuccess("No id property") id <- justMessage(fromTryCatch(UUID.fromString(str))) } yield id extractId(Map.empty) extractId(Map("id" -> "notUuid")) extractId(Map("id" -> UUID.randomUUID.toString)) Failure(No id property) Failure(Invalid UUID string: notUuid) Success(f6af15db-feeb-4895-8c67-a70a6f947db9)
  • 105. Aside: Monadic DSL def justMessage[S]( v: Validation[Throwable, S]): Validation[String, S] = v.<-: { _.getMessage } def extractId( metadata: Map[String, String]): Validation[String, UUID] = for { str <- metadata.get("id").toSuccess("No id property") id <- justMessage(fromTryCatch(UUID.fromString(str))) } yield id extractId(Map.empty) extractId(Map("id" -> "notUuid")) extractId(Map("id" -> UUID.randomUUID.toString)) This reads pretty naturally!
  • 106. Aside: Monadic DSL def justMessage[S]( v: Validation[Throwable, S]): Validation[String, S] = v.<-: { _.getMessage } def extractId( metadata: Map[String, String]): Validation[String, UUID] = for { str <- metadata.get("id").toSuccess("No id property") id <- justMessage(fromTryCatch(UUID.fromString(str))) } yield id extractId(Map.empty) extractId(Map("id" -> "notUuid")) extractId(Map("id" -> UUID.randomUUID.toString)) This doesn’t! Notation is inside-out!
  • 107. Aside: Monadic DSL import scalaz.syntax.id._ def justMessage[S]( v: Validation[Throwable, S]): 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
  • 108. Validation • Monadic usage of Validation is incredibly useful • As useful as monadic option but provides why failures have occurred • Can it get better?
  • 109. Validation is Applicative... ... if the error type is Semigroup
  • 110. Validation is Applicative... ... if the error type is Semigroup Which of these are applicative? Validation[Int, Any] Validation[Any, Int] Validation[List[String], String] Validation[String, Int]
  • 111. Validation is Applicative... ... if the error type is Semigroup Which of these are applicative? ✔ Validation[Int, Any] Validation[Any, Int] Validation[List[String], String] Validation[String, Int]
  • 112. Validation is Applicative... ... if the error type is Semigroup Which of these are applicative? ✔ Validation[Int, Any] ✘ Validation[Any, Int] Validation[List[String], String] Validation[String, Int]
  • 113. Validation is Applicative... ... if the error type is Semigroup Which of these are applicative? ✔ Validation[Int, Any] ✘ Validation[Any, Int] ✔ Validation[List[String], String] Validation[String, Int]
  • 114. Validation is Applicative... ... if the error type is Semigroup Which of these are applicative? ✔ Validation[Int, Any] ✘ Validation[Any, Int] ✔ Validation[List[String], String] ✔ Validation[String, Int]
  • 117. Validation[List[_], _] Validation[List[String], Int] Success(42) Failure(List(“Tigers”, “Lions”, “Bears”))
  • 118. Validation[List[_], _] Validation[List[String], Int] Success(42) Failure(List(“Tigers”, “Lions”, “Bears”)) Failure(List())
  • 119. Validation[List[_], _] Validation[List[String], Int] Success(42) Failure(List(“Tigers”, “Lions”, “Bears”)) Failure(List()) Failure of no errors? Can we do better? Use the type system?
  • 120. ValidationNEL Validation[NonEmptyList[String], Int] Success(42) Failure(NonEmptyList( “Tigers”, “Lions”, “Bears”))
  • 121. ValidationNEL Validation[NonEmptyList[String], Int] Success(42) Failure(NonEmptyList( “Tigers”, “Lions”, “Bears”)) This is so common, there’s an alias for it: ValidationNEL[String, Int]
  • 122. ValidationNEL Validation[NonEmptyList[String], Int] Success(42) Failure(NonEmptyList( “Tigers”, “Lions”, “Bears”)) This is so common, there’s an alias for it: ValidationNEL[String, Int] And any Validation[E, S] can be converted to ValidationNEL[E, S]: v.toValidationNEL
  • 123. Putting together the pieces • Given a map of string 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
  • 124. Putting together the pieces case class Employee( name: String, level: Int, manager: Boolean) type Metadata = Map[String, String]
  • 125. Putting together the pieces def justMessage[S]( v: Validation[Throwable, S]): Validation[String, S] = v.<-: { _.getMessage } def extractString( metadata: Metadata, key: String): Validation[String, String] = metadata. get(key). toSuccess("Missing required property %s".format(key))
  • 126. Putting together the pieces def extractName( metadata: Metadata): Validation[String, String] = extractString(metadata, "name") flatMap { name => if (name.isEmpty) "Must have a non-empty name!".fail else name.success }
  • 127. Putting together the pieces def extractLevel( metadata: Metadata): Validation[String, Int] = extractString(metadata, "level"). flatMap { _.parseInt |> justMessage }. flatMap { level => if (level < 1) "Level must be at least 1".fail else if (level > 15) "Really?".fail else level.success }
  • 128. Putting together the pieces def extractManager( metadata: Metadata): Validation[String, Boolean] = extractString(metadata, "manager"). flatMap { _.parseBoolean |> justMessage }
  • 129. Putting together the pieces def extractEmployee( metadata: Metadata): ValidationNEL[String, Employee] = { extractName(metadata).toValidationNel |@| extractLevel(metadata).toValidationNel |@| extractManager(metadata).toValidationNel } apply Employee.apply
  • 130. Putting together the pieces extractEmployee(Map( "name" -> "Turing", "level" -> "15", "manager" -> "false")) extractEmployee(Map( "name" -> "Turing", "level" -> "0", "manager" -> "true")) extractEmployee(Map( "name" -> "Turing", "level" -> "17", "manager" -> "true"))
  • 131. Putting together the pieces extractEmployee(Map( "name" -> "Turing", Success(Employee(Turing,15,false)) "level" -> "15", "manager" -> "false")) extractEmployee(Map( "name" -> "Turing", "level" -> "0", "manager" -> "true")) extractEmployee(Map( "name" -> "Turing", "level" -> "17", "manager" -> "true"))
  • 132. Putting together the pieces extractEmployee(Map( "name" -> "Turing", Success(Employee(Turing,15,false)) "level" -> "15", "manager" -> "false")) extractEmployee(Map( "name" -> "Turing", Failure(NonEmptyList(Level "level" -> "0", must be at least 1)) "manager" -> "true")) extractEmployee(Map( "name" -> "Turing", "level" -> "17", "manager" -> "true"))
  • 133. Putting together the pieces extractEmployee(Map( "name" -> "Turing", Success(Employee(Turing,15,false)) "level" -> "15", "manager" -> "false")) extractEmployee(Map( "name" -> "Turing", Failure(NonEmptyList(Level "level" -> "0", must be at least 1)) "manager" -> "true")) extractEmployee(Map( "name" -> "Turing", "level" -> "17", Failure(NonEmptyList(Really?)) "manager" -> "true"))
  • 134. Putting together the pieces extractEmployee(Map( "name" -> "Turing")) extractEmployee(Map( "name" -> "", "level" -> "17", "manager" -> "notBool"))
  • 135. Putting together the pieces extractEmployee(Map( Failure(NonEmptyList( "name" -> "Turing")) Missing required property level, Missing required property manager)) extractEmployee(Map( "name" -> "", "level" -> "17", "manager" -> "notBool"))
  • 136. Putting together the pieces extractEmployee(Map( Failure(NonEmptyList( "name" -> "Turing")) Missing required property level, Missing required property manager)) extractEmployee(Map( Failure(NonEmptyList( "name" -> "", Must have a non-empty name!, "level" -> "17", Really?, "manager" -> "notBool")) For input string: "notBool"))
  • 137. Putting together the pieces • Building upon previous example, given a list of metadata, produce a list of employees or a list of errors
  • 138. Putting together the pieces def extractEmployees( metadata: List[Metadata] ): ValidationNEL[String, List[Employee]] = ???
  • 139. Putting together the pieces def extractEmployees( metadata: List[Metadata] ): ValidationNEL[String, List[Employee]] = { val vEmps: List[ValidationNEL[String, Employee]] = metadata map extractEmployee ??? }
  • 140. Putting together the pieces def extractEmployees( metadata: List[Metadata] ): ValidationNEL[String, List[Employee]] = { How can we swap order of ValidationNEL and List? val vEmps: List[ValidationNEL[String, Employee]] = metadata map extractEmployee ??? }
  • 141. Putting together the pieces def extractEmployees( metadata: List[Metadata] ): ValidationNEL[String, 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
  • 142. Type Lambdas sequence[({type λ[a] = ValidationNEL[String, a]})#λ, Employee]
  • 143. Type Lambdas sequence[({type λ[a] = ValidationNEL[String, a]})#λ, Employee] Defines an anonymous structural type with one member, λ[a]
  • 144. Type Lambdas sequence[({type λ[a] = ValidationNEL[String, a]})#λ, Employee] Defines type λ[a] as an alias for ValidationNEL[String, a]
  • 145. Type Lambdas sequence[({type λ[a] = ValidationNEL[String, a]})#λ, Employee] References the λ member of the structural type
  • 146. Type Lambdas sequence[λ[a] = ValidationNEL[String, a], Employee] Not valid Scala syntax, but IntelliJ will render type lambdas this way
  • 147. Type Lambdas sequence[ValidationNEL[String, _], Employee] Can be thought of this way (sort of)
  • 148. Lens: Problem Statement case class Contact( name: Name, phone: Phone) case class Name( salutation: String, first: String, last: String) case class Phone( digits: String) val seth = Contact( Name("Mr.", "Seth", "Avett"), Phone("555-5555"))
  • 149. Lens: Problem Statement case class Contact( name: Name, phone: Phone) We need a copy of seth case class Name( salutation: String, with first name set to first: String, “Scott” last: String) case class Phone( digits: String) val seth = Contact( Name("Mr.", "Seth", "Avett"), Phone("555-5555"))
  • 150. Lens: Problem Statement val seth = Contact( Name("Mr.", "Seth", "Avett"), Phone("555-5555")) val scott = seth.copy( name = seth.name.copy(first = "Scott"))
  • 151. Lens: Problem Statement val seth = Contact( Name("Mr.", "Seth", "Avett"), Phone("555-5555")) val scott = seth.copy( name = seth.name.copy(first = "Scott")) Doesn’t scale - each layer in record structure results in another layer of copies and duplication
  • 152. Lens • Given a record type and a field, a lens provides the ability to focus on the specified field, which allows accessing the field value and setting the field value (immutably)
  • 153. Lens • Given a record type and a field, a 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
  • 154. Lens case class Contact( Record Type Field Type name: Name, phone: Phone) val contactNameLens = Lens.lensu[Contact, Name]( (c, n) => c.copy(name = n), _.name) Setter Getter val contactPhoneLens = Lens.lensu[Contact, Phone]( (c, p) => c.copy(phone = p), _.phone) Setter Getter
  • 155. Lens •Case class lenses usually use copy in setter case class Contact( name: Name, phone: Phone) val contactNameLens = Lens.lensu[Contact, Name]( (c, n) => c.copy(name = n), _.name) Setter Getter val contactPhoneLens = Lens.lensu[Contact, Phone]( (c, p) => c.copy(phone = p), _.phone) Setter Getter
  • 156. Lens •Case class lenses usually use copy in setter case class Contact( •Case class lenses are purely mechanical to name: Name, author (there’s even a compiler plugin that phone: Phone) does it!) val contactNameLens = Lens.lensu[Contact, Name]( (c, n) => c.copy(name = n), _.name) Setter Getter val contactPhoneLens = Lens.lensu[Contact, Phone]( (c, p) => c.copy(phone = p), _.phone) Setter Getter
  • 157. Lens case class Name( salutation: String, first: String, last: String) val nameSalutationLens = Lens.lensu[Name, String]( (n, s) => n.copy(salutation = s), _.salutation) val nameFirstLens = Lens.lensu[Name, String]( (n, f) => n.copy(first = f), _.first) val nameLastLens = Lens.lensu[Name, String]( (n, l) => n.copy(last = l), _.last)
  • 158. Lens case class Phone( digits: String) val phoneDigitsLens = Lens.lensu[Phone, String]( (p, d) => p.copy(digits = d), _.digits)
  • 159. Lens Lenses compose!! val contactFirstNameLens = contactNameLens >=> nameFirstLens Composes 2 lenses in to a Contact to First Name lens via andThen
  • 160. Lens Lenses compose!! val contactFirstNameLens = contactNameLens >=> nameFirstLens Composes 2 lenses in to a Contact to First Name lens via andThen val seth = Contact( Name("Mr.", "Seth", "Avett"), Phone("555-5555"))
  • 161. Lens Lenses compose!! val contactFirstNameLens = contactNameLens >=> nameFirstLens Composes 2 lenses in to a Contact to First Name lens via andThen val seth = Contact( Name("Mr.", "Seth", "Avett"), Phone("555-5555")) contactFirstNameLens.get(seth) “Seth”
  • 162. Lens Lenses compose!! val contactFirstNameLens = contactNameLens >=> nameFirstLens Composes 2 lenses in to a Contact to First Name lens via andThen val seth = Contact( Name("Mr.", "Seth", "Avett"), Phone("555-5555")) contactFirstNameLens.get(seth) “Seth” contactFirstNameLens.set(seth, "Scott") Contact(Name(Mr.,Scott,Avett),Phone(555-5555))
  • 163. Future Topics • Zipper • Reader • Arrow • Writer • Kleisli • State • Category • Monad • Iteratees Transformers ...and much more!

Notas del editor

  1. \n
  2. \n
  3. \n
  4. \n
  5. \n
  6. \n
  7. \n
  8. \n
  9. \n
  10. \n
  11. \n
  12. \n
  13. \n
  14. \n
  15. \n
  16. \n
  17. \n
  18. \n
  19. \n
  20. \n
  21. \n
  22. \n
  23. \n
  24. \n
  25. \n
  26. \n
  27. \n
  28. \n
  29. \n
  30. \n
  31. \n
  32. \n
  33. \n
  34. \n
  35. \n
  36. \n
  37. \n
  38. \n
  39. \n
  40. \n
  41. \n
  42. \n
  43. \n
  44. \n
  45. \n
  46. \n
  47. \n
  48. \n
  49. \n
  50. \n
  51. \n
  52. \n
  53. \n
  54. \n
  55. \n
  56. \n
  57. \n
  58. \n
  59. \n
  60. \n
  61. \n
  62. \n
  63. \n
  64. \n
  65. \n
  66. \n
  67. \n
  68. \n
  69. \n
  70. \n
  71. \n
  72. \n
  73. \n
  74. \n
  75. \n
  76. \n
  77. \n
  78. \n
  79. \n
  80. \n
  81. \n
  82. \n
  83. \n
  84. \n
  85. \n
  86. \n
  87. \n
  88. \n
  89. \n
  90. \n
  91. \n
  92. \n
  93. \n
  94. \n
  95. \n
  96. \n
  97. \n
  98. \n
  99. \n
  100. \n
  101. \n
  102. \n
  103. \n
  104. \n
  105. \n
  106. \n
  107. \n
  108. \n
  109. \n
  110. \n
  111. \n
  112. \n
  113. \n
  114. \n
  115. \n
  116. \n
  117. \n
  118. \n
  119. \n
  120. \n
  121. \n
  122. \n
  123. \n
  124. \n
  125. \n
  126. \n
  127. \n
  128. \n
  129. \n
  130. \n
  131. \n
  132. \n
  133. \n
  134. \n
  135. \n
  136. \n
  137. \n
  138. \n
  139. \n
  140. \n
  141. \n
  142. \n
  143. \n
  144. \n
  145. \n
  146. \n
  147. \n
  148. \n
  149. \n
  150. \n