Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Scalaz: The Easy Parts

Scalaz: The Easy Parts

A gentle introduction to Scalaz.

Taylor Leese

October 07, 2012
Tweet

Other Decks in Technology

Transcript

  1. Scalaz: The Easy Parts https://speakerdeck.com/u/taylorleese/p/scalaz-easy-parts * introduction to the simpler

    scalaz concepts and data structures * knowledge of Scala is assumed * no prior knowledge of category theory is assumed
  2. Who am I? Taylor Leese Engineering Manager @ StackMob Twitter:

    @taylorleese GitHub: https://github.com/taylorleese
  3. WTF is Scalaz? * extension to the core scala library

    * includes many functional programming constructs * monads, monoids, applicatives, etc.
  4. “If you are thinking of using Scalaz, stop now while

    you still have your sanity!" * source: http://zeroturnaround.com/blog/scala-sink-or-swim-part-1/#scalaz
  5. “...it will not immediately help you write better programs that

    are easy to understand.” * source: http://zeroturnaround.com/blog/scala-sink-or-swim-part-1/#scalaz
  6. “There are only two kinds of languages: the ones people

    complain about and the ones nobody uses.” - Bjarne Stroustrup * applicable to libraries as well * source: http://www.stroustrup.com/bs_faq.html#really-say-that
  7. @ StackMob we use Scala(z) in all our services *

    mostly engineers with non functional backgrounds who came up to speed on scalaz and FP concepts * our code is cleaner and more expressive from using it
  8. libraryDependencies += “org.scalaz” %% “scalaz-core” % “6.0.4” import scalaz._ import

    Scalaz._ * https://github.com/scalaz/scalaz/blob/master/core/src/main/scala/scalaz/Scalaz.scala
  9. To follow along... 1. brew install sbt 2. git clone

    [email protected]:taylorleese/scalaz-example-sbt.git 3. cd scalaz-example-sbt 4. sbt console 5. import scalaz._; import Scalaz._
  10. Have you written this? val x: Option[Int] = Option(1) val

    y: Any = x match { case Some(i) => i case None => “foo” } It’s not very typesafe.
  11. some/none val x: Option[Int] = Option(1) val y: Int =

    x some { i => i } none { 0 } Typesafe. This won’t even compile... val x: Option[Int] = Option(1) val y: Any = x some { i => i } none { “foo” }
  12. fold val x: Option[Int] = Option(1) val y: Int =

    x.fold[Int]( some = i => i none = 0 ) Another typesafe match.
  13. | val x: Option[Int] = Option(1) val y: Int =

    x | 0 A better getOrElse. Defined as... def |(a: => A): A = value getOrElse a
  14. .some and none[T] val x = “foo”.some val y: Option[String]

    = Some(foo) val x = none[String] val y: Option[String = None Some and None sugar.
  15. option > def f: String = “foo” f: java.lang.String >

    true.option(f) Option[java.lang.String] = Some(foo) > false.option(f) Option[java.lang.String] = None If true Some else None. val b: Boolean = ... if (b) { Some(f) } else { None }
  16. fold val x: Boolean = true val y: String =

    x.fold[String]( a = “iAmTrue” b = “iAmFalse” ) A typesafe if/else.
  17. === val s1: String = “foo” val s2: String =

    “foo” val i: Int = 1 s1 === s2 s1 === 1 // does not compile Typesafe equals. (awyeah)
  18. /== val s1: String = “foo” val s2: String =

    “bar” val i: Int = 1 s1 /== s2 s1 /== 1 // does not compile Typesafe not equals. (awyeah)
  19. How does this work? def equalA[A]: Equal[A] = new Equal[A]

    with NaturalEqual { def equal(a1: A, a2: A) = a1 == a2 } Magic? Defined in trait Equals. Defined in Identity[A]. def ===(a: A)(implicit e: Equal[A]): Boolean = e equal (value, a) * string implicitly converted to Identity[String] * https://github.com/scalaz/scalaz/blob/master/core/src/main/scala/scalaz/Identity.scala
  20. Defining a custom Equal[A] case class Foo(x: String) implicit val

    fooEqual: Equal[Foo] = equalA val f1 = new Foo(“bar”) val f2 = new Foo(“bar”) f1 === f2
  21. ~ val w = none[Boolean] val x = ~w //

    w | false val y = “foo”.some val z = ~y // y | “” Implicit zero with primitive types. How does this work? def unary_~(implicit z: Zero[A]): A = { value getOrElse z.zero } OptionW[A]
  22. Defining a custom Zer0[Z] case class Foo(s: String) implicit val

    fooZero: Zero[Foo] = { new Zero[Foo] { override val zero: Foo = Foo(“”) } } val x: Option[Foo] = none[Foo] val y: Foo = ~x // x | zero
  23. Typesafe non-empty lists val x: NonEmptyList[String] = nel(“foo”) List =>

    Option[NonEmptyList] => Option[List] val x: List[Int] = List(1,2,3) val y: Option[NonEmptyList[Int]] = x.toNel val z: Option[List[Int]] = y.map(_.list) * impossible to create a NonEmptyList that is empty
  24. Have you written this? try { mayThrow() } catch {

    case e => ... } Compiler can’t enforce type safety on errors. There are no checked exceptions in Scala ...and this catch may not even be written
  25. WTF is Validation? final case class Success[E, A](a: A) extends

    Validation[E, A] final case class Failure[E, A](e: E) extends Validation[E, A] Represents failure and success. * similar to Either with Left and Right, but with less obscure names
  26. Using Validation def mayThrow(): T = ... val r: Validation[Throwable,

    T] = try { mayThrow().success } catch { case e => e.fail } Typesafety and defined error conditions. * failure case does not need to be a Throwable
  27. map/flatMap val x: Validation[String, Int] = 1.success val y: Validation[String,

    Int] = x.map(_ + 1) val z: Validation[String, Int] = { x.flatMap(i => (i + 1).success) }
  28. fold val r: Validation[String, Int] = 1.success val x: String

    = r.fold[String]( success = i => i.toString failure = s => s )
  29. toOption val r: Validation[String, Int] = 1.success val x: Option[Int]

    = r.toOption // some if success; none otherwise
  30. validating(...) def validating[A](a: => A): Validation[Throwable, A] = a.pure[Function0].throws Utility

    method for creating Validations. pure “lifts” a into a Function0 def throws: Validation[Throwable, T] = try { success(a()) } catch { case e => failure(e) } (Function0W) * https://github.com/scalaz/scalaz/blob/master/core/src/main/scala/scalaz/Function0W.scala
  31. ValidationNEL type ValidationNEL[E, A] = Validation[NonEmptyList[E], A] Use it to

    accumulate errors. * failure case does not need to be a Throwable
  32. Applicative Builder scala> (Set(1).successNel[String] |@| Set(1,2).successNel[String]) { _ ++ _

    } res0: scalaz.Validation[scalaz.NonEmptyList[String],scala.collection.immutable.Set[Int]] = Success(Set(1, 2)) scala> (Set(1).successNel[String] |@| "error2".failNel[Set[String]]) { _ ++ _ } res2: scalaz.Validation[scalaz.NonEmptyList[String],scala.collection.immutable.Set[Any]] = Failure(NonEmptyList(error2)) scala> ("error1".failNel[Set[String]] |@| "error2".failNel[Set[String]]) { _ ++ _ } res3: scalaz.Validation[scalaz.NonEmptyList[java.lang.String],scala.collection.immutable.Set[String]] = Failure(NonEmptyList(error1, error2)) Use |@| to reduce Validations. Borderline not an easy part, but shown here to display it’s power. * https://github.com/scalaz/scalaz/blob/master/core/src/main/scala/scalaz/ApplicativeBuilder.scala * lift-json-scalaz uses this for parsing json https://github.com/lift/framework/tree/master/core/json-scalaz
  33. Using IO scala> val x = io { println("hi") }

    x: scalaz.effects.IO[Unit] = scalaz.effects.IO$$anon $2@13d5047e scala> x.unsafePerformIO hi IO (side-effects) only happen when you call unsafePerformIO
  34. IO is Composable scala> val x: IO[Unit] = for {

    | _ <- io { println("hi") } | _ <- io { println("there") } | } yield () x: scalaz.effects.IO[Unit] = scalaz.effects.IO$$anon $2@3195df2f scala> x.unsafePerformIO hi there
  35. Handling Exceptions scala> val y = io { throw new

    Exception("error"); () } y: scalaz.effects.IO[Unit] = scalaz.effects.IO$$anon $2@5d3818c2 scala> val z = y.except { e => io { println(e.getMessage) } } z: scalaz.effects.IO[Unit] = scalaz.effects.IO$$anon $2@37dd016f scala> z.unsafePerformIO error
  36. Create an Actor def perform(f: () => Unit) { f()

    } val a: Actor[() => Unit] = actor(perform)
  37. Actors are Async val a: Actor[() => Unit] = ...

    def op(): Unit = ... a { () => op } // using apply a ! { () => op } // using ! Fire and forget.
  38. Execute an Expression Async def f(): T = ... val

    x: Promise[T] = promise { f } val y: T = x.get // block until finished
  39. Promises are Composable val x: Promise[Int] = promise { 1

    } val y: Promise[Int] = x.map { _ + 1 } val z: Int = y.get // z = 2
  40. Using to and errorTo def f(): T = ... def

    handleResult(r: T): Unit = ... def handleError(t: Throwable): Unit = ... val p: Promise[T] = promise { f } p.to(handleResult(_)) p.errorTo(handleError(_)) Don’t block.
  41. Additional Resources • Learning Scalaz - http://eed3si9n.com/learning-scalaz-day1 (day 1 to

    17+) • Learn You a Scalaz - https://github.com/jrwest/learn_you_a_scalaz • Scalaz For the Rest of Us - http://arosien.github.com/scalaz-base-talk-201208 • Scalaz on GitHub - https://github.com/scalaz/scalaz • Comprehending Monads - http://marakana.com/static/courseware/scala/ presentation/comprehending-monads.html