SlideShare a Scribd company logo
Validation with Functional Programming
Sukant Hajra / @shajra
April 14, 2016
Sukant Hajra / @shajra Validation with Functional Programming April 14, 2016 1 / 61
Some Goals
explore data structures for managing errors
use type classes to get nice APIs (DSLs)
see some examples with parsing
Sukant Hajra / @shajra Validation with Functional Programming April 14, 2016 2 / 61
scalaz./
Construction
scala> import scalaz.syntax.either._
import scalaz.syntax.either._
scala> 1.right[String]
res0: scalaz./[String,Int] = /-(1)
scala> "fail".left[Int]
res1: scalaz./[String,Int] = -/(fail)
Sukant Hajra / @shajra Validation with Functional Programming April 14, 2016 3 / 61
scalaz./
Monadic Syntax
scala> 1.right[String].flatMap { a =>
| 2.right[String].map { b =>
| a + b
| }
| }
res2: scalaz./[String,Int] = /-(3)
scala> for {
| a <- 1.right[String]
| b <- 2.right[String]
| } yield a + b
res3: scalaz./[String,Int] = /-(3)
Sukant Hajra / @shajra Validation with Functional Programming April 14, 2016 4 / 61
scalaz./
Applicative Syntax
scala> import scalaz.syntax.apply._
import scalaz.syntax.apply._
scala> 1.right[String] |@| 2.right[String] apply { _ + _ }
res4: scalaz./[String,Int] = /-(3)
Sukant Hajra / @shajra Validation with Functional Programming April 14, 2016 5 / 61
scalaz./
Semantics
scala> (1.right[String] |@| 2.right[String]).
| apply { _ + _ }
res5: scalaz./[String,Int] = /-(3)
scala> (1.right[String] |@| "fail 2".left[Int]).
| apply { _ + _ }
res6: scalaz./[String,Int] = -/(fail 2)
scala> ("fail 1".left[Int] |@| 2.right[String]).
| apply { _ + _ }
res7: scalaz./[String,Int] = -/(fail 1)
scala> ("fail 1".left[Int] |@| "fail 2".left[Int]).
| apply { _ + _ }
res8: scalaz./[String,Int] = -/(fail 1)
Sukant Hajra / @shajra Validation with Functional Programming April 14, 2016 6 / 61
scalaz.ValidationNel
Construction
scala> import scalaz.syntax.validation._
import scalaz.syntax.validation._
scala> 1.success[String]
res9: scalaz.Validation[String,Int] = Success(1)
scala> "fail".failure[Int]
res10: scalaz.Validation[String,Int] = Failure(fail)
scala> 1.successNel[String]
res11: scalaz.ValidationNel[String,Int] = Success(1)
scala> "fail".failureNel[Int]
res12: scalaz.ValidationNel[String,Int] =
Failure(NonEmptyList(fail))
Sukant Hajra / @shajra Validation with Functional Programming April 14, 2016 7 / 61
scalaz.ValidationNel
Semantics
scala> (1.successNel[String] |@| 2.successNel[String]).
| apply { _ + _ }
res13: scalaz.Validation[scalaz.NonEmptyList[String],Int] =
Success(3)
scala> (1.successNel[String] |@| "fail 2".failureNel[Int]).
| apply { _ + _ }
res14: scalaz.Validation[scalaz.NonEmptyList[String],Int] =
Failure(NonEmptyList(fail 2))
scala> ("fail 1".failureNel[Int] |@| "fail 2".failureNel[Int]).
| apply { _ + _ }
res15: scalaz.Validation[scalaz.NonEmptyList[String],Int] =
Failure(NonEmptyList(fail 1, fail 2))
Sukant Hajra / @shajra Validation with Functional Programming April 14, 2016 8 / 61
scalaz.ValidationNel
Dangerous flatMap
scala> "fail 1".failureNel[Int].flatMap { a =>
| "fail 2".failureNel[Int].map { b =>
| a + b
| }
| }
warning: there was one deprecation warning; re-run with
-deprecation for details
res16: scalaz.Validation[scalaz.NonEmptyList[String],Int] =
Failure(NonEmptyList(fail 1))
Sukant Hajra / @shajra Validation with Functional Programming April 14, 2016 9 / 61
Composition
Defining some functions
import scalaz.std.function._
import scalaz.syntax.compose._
def add: Int => Int => Int = a => b => a + b
val mult: Int => Int => Int = a => b => a * b
Usage
scala> add(2) >>> mult(10) >>> add(3) apply 0
res18: Int = 23
scala> add(2) <<< mult(10) <<< add(3) apply 0
res19: Int = 32
Sukant Hajra / @shajra Validation with Functional Programming April 14, 2016 10 / 61
What more is possible?
Consider this broken config
val confText = """
name = "Donald Trump"
year_born = 1946
nemesis {
year_born = "Age of Enlightment"
name = 1650
}
"""
Both nemesis.year_born and nemesis.name have the wrong type.
Sukant Hajra / @shajra Validation with Functional Programming April 14, 2016 11 / 61
What more is possible?
Could we catch both defects with this API?
case class UserData(name: String, yearBorn: Int)
def sub(key: String): ConfRead[Json] = ???
def required[A : Readable](key: String): ConfRead[A] = ???
val userRead: ConfRead[UserData] =
(required[String]("name") |@| required[Int]("year_born")).
apply(UserData)
def fullRead: ConfRead[(UserData, UserData)] =
(userRead |@| (sub("nemesis") >>> userRead)).tupled
Config.parse map fullRead.read
Sukant Hajra / @shajra Validation with Functional Programming April 14, 2016 12 / 61
Type Classes (a review)
Sukant Hajra / @shajra Validation with Functional Programming April 14, 2016 13 / 61
Useful type classes
We’ll quickly review:
Semigroup
Compose
Covariant Functor
Applicative Functor
Monad
Also useful, but not discussed today:
Profunctor
Arrow or Strong Profunctor
Sukant Hajra / @shajra Validation with Functional Programming April 14, 2016 14 / 61
High quality type classes
Type classes are statically dispatched interfaces that should
be implementable for many data types
provide functions that lead to rich libraries
have only one instance per type (global uniqueness) 1
have laws (strong contracts).
Auto-deriving instances is also nice.
1
Global uniqueness is debated by a few
Sukant Hajra / @shajra Validation with Functional Programming April 14, 2016 15 / 61
Semigroup
Definition
trait Semigroup[A] {
def append(x: A, y: A): A
}
object Semigroup {
def apply[A](implicit ev: Semigroup[A]): Semigroup[A] = ev
}
Sukant Hajra / @shajra Validation with Functional Programming April 14, 2016 16 / 61
Semigroup
Laws
trait SemigroupLaws[A] extends Semigroup[A] {
def semigroupAssociativity(x: A, y: A, z: A) =
append(x, append(y, z)) == append(append(x, y), z)
}
Sukant Hajra / @shajra Validation with Functional Programming April 14, 2016 17 / 61
Semigroup
Syntax
implicit class SemigroupOps[A : Semigroup](a1: A) {
def |+|(a2: A): A = Semigroup[A].append(a1, a2)
}
Sukant Hajra / @shajra Validation with Functional Programming April 14, 2016 18 / 61
Compose
Definition
trait Compose[F[_, _]] {
def compose[A, B, C](fbc: F[B, C], fab: F[A, B]): F[A, C]
}
object Compose {
def apply[F[_, _]](implicit ev: Compose[F]): Compose[F] = ev
}
Sukant Hajra / @shajra Validation with Functional Programming April 14, 2016 19 / 61
Compose
Laws
trait ComposeLaws[F[_, _]] extends Compose[F] {
def composeAssociativity[A, B, C, D]
(fab: F[A, B], fbc: F[B, C], fcd: F[C, D]) =
compose(fcd, compose(fbc, fab)) ==
compose(compose(fcd, fbc), fab)
}
Sukant Hajra / @shajra Validation with Functional Programming April 14, 2016 20 / 61
Compose
Syntax
implicit class ComposeOps[F[_, _], A, B](f1: F[A, B])(
implicit ev: Compose[F]) {
def <<<[C](f2: F[C, A]): F[C, B] = Compose[F].compose(f1, f2)
def >>>[C](f2: F[B, C]): F[A, C] = Compose[F].compose(f2, f1)
}
Sukant Hajra / @shajra Validation with Functional Programming April 14, 2016 21 / 61
(Covariant) Functor
Definition
trait Functor[F[_]] {
def map[A, B](fa: F[A])(f: A => B): F[B]
}
object Functor {
def apply[F[_]](implicit ev: Functor[F]): Functor[F] = ev
}
Sukant Hajra / @shajra Validation with Functional Programming April 14, 2016 22 / 61
(Covariant) Functor
Laws
trait FunctorLaws[F[_]] extends Functor[F] {
def functorIdentity[A](fa: F[A]) =
map(fa)(identity[A]) == fa
def functorComposition[A, B, C]
(fa: F[A], f: A => B, g: B => C) =
map(map(fa)(f))(g) == map(fa)(f andThen g)
}
Sukant Hajra / @shajra Validation with Functional Programming April 14, 2016 23 / 61
Functor
Syntax
implicit class FunctorOps[F[_] : Functor, A](fa: F[A]) {
def map[B](f: A => B): F[B] = Functor[F].map(fa)(f)
def fpair: F[(A, A)] = map { a => (a, a) }
def fproduct[B](f: A => B): F[(A, B)] =
map { a => (a, f(a)) }
}
Sukant Hajra / @shajra Validation with Functional Programming April 14, 2016 24 / 61
Applicative (Functor)
Definition
trait Applicative[F[_]] extends Functor[F] {
def pure[A](a: A): F[A]
def ap[A, B](fa: F[A])(fab: F[A => B]): F[B]
}
object Applicative {
def apply[F[_]](implicit ev: Applicative[F])
: Applicative[F] = ev
}
Sukant Hajra / @shajra Validation with Functional Programming April 14, 2016 25 / 61
Applicative (Functor)
Laws
trait ApplicativeLaws1[F[_]] extends
Applicative[F] with
FunctorLaws[F] {
def applicativeIdentity[A](fa: F[A]) =
ap(fa)(pure[A => A](identity)) == fa
def applicativeHomomorphism[A, B](a: A, ab: A => B) =
ap(pure(a))(pure(ab)) == pure(ab(a))
def applicativeInterchange[A, B](a: A, f: F[A => B]) =
ap(pure(a))(f) == ap(f)(pure { (ff: A => B) => ff(a) })
}
Sukant Hajra / @shajra Validation with Functional Programming April 14, 2016 26 / 61
Applicative (Functor)
Laws
trait ApplicativeLaws2[F[_]] extends ApplicativeLaws1[F] {
def applicativeDerivedMap[A, B](f: A => B, fa: F[A]) =
map(fa)(f) == ap(fa)(pure(f))
def applicativeComposition[A, B, C]
(fa: F[A], fab: F[A => B], fbc: F[B => C]) =
ap(ap(fa)(fab))(fbc) ==
ap(fa)(
ap(fab)(
map[B=>C, (A=>B)=>(A=>C)](fbc) {
bc => ab => bc compose ab }))
}
Sukant Hajra / @shajra Validation with Functional Programming April 14, 2016 27 / 61
Applicative (Functor)
Syntax
implicit class ApplicativeOps1[F[_] : Applicative, A](
fa: F[A]) {
def <*>[A, B](f: F[A => B]) = Applicative[F].ap(fa)(f)
def *>[B](fb: F[B]): F[B] =
Applicative[F].ap(fa)(Functor[F].map(fb)(Function.const))
def <*[B](fb: F[B]): F[A] =
Applicative[F].ap(fb)(fa map Function.const)
}
implicit class ApplicativeOps2[A](a: A) {
def pure[F[_] : Applicative]: F[A] = Applicative[F].pure(a)
}
Sukant Hajra / @shajra Validation with Functional Programming April 14, 2016 28 / 61
Monad
Definition
trait Monad[F[_]] extends Applicative[F] {
def bind[A, B](fa: F[A])(fab: A => F[B]): F[B]
}
object Monad {
def apply[F[_]](implicit ev: Monad[F]): Monad[F] = ev
}
Sukant Hajra / @shajra Validation with Functional Programming April 14, 2016 29 / 61
Monad
Laws
trait MonadLaws[F[_]] extends Monad[F] {
def monadRightIdentity[A](fa: F[A]) =
bind(fa)(pure) == fa
def monadLeftIdentity[A, B](a: A, f: A => F[B]) =
bind(pure(a))(f) == f(a)
def monadAssociativity[A, B, C]
(fa: F[A], f: A => F[B], g: B => F[C]) =
bind(bind(fa)(f))(g) == bind(fa) { a => bind(f(a))(g) }
def monadDerivedAp[A, B](fab: F[A => B], fa: F[A]) =
bind(fa) { a => map(fab) { f => f(a) } } == ap(fa)(fab)
}
Sukant Hajra / @shajra Validation with Functional Programming April 14, 2016 30 / 61
Monad
Syntax
implicit class MonadOps[F[_] : Monad, A](fa: F[A]) {
def flatMap[B](f: A => F[B]): F[B] = Monad[F].bind(fa)(f)
def >>=[B](f: A => F[B]): F[B] = flatMap(f)
def >>![B](f: A => F[B]): F[A] =
flatMap { a => Monad[F].map(f(a)) { b => a } }
def >>[B](fb: F[B]): F[B] = flatMap(Function.const(fb))
import scalaz.Leibniz.===
def join[B](implicit ev: A === F[B]): F[B] =
Monad[F].bind(ev.subst[F](fa))(identity)
}
Sukant Hajra / @shajra Validation with Functional Programming April 14, 2016 31 / 61
Data types
Sukant Hajra / @shajra Validation with Functional Programming April 14, 2016 32 / 61
Non-empty List
Definition
object nel {
case class Nel[A](head: A, tail: List[A]) {
def toList: List[A] = head :: tail
override def toString: String =
s"""Nel(${head}, ${tail mkString ","})"""
}
object Nel {
def of[A](head: A, tail: A*): Nel[A] =
new Nel(head, tail.toList)
}
}; import nel._
Sukant Hajra / @shajra Validation with Functional Programming April 14, 2016 33 / 61
Non-empty List
Semigroup Instance
import scalaz.Semigroup
import scalaz.std.list._
import scalaz.syntax.semigroup._
implicit def nelSemigroup[A]: Semigroup[Nel[A]] =
new Semigroup[Nel[A]] {
def append(x: Nel[A], y: => Nel[A]) =
Nel[A](x.head, x.tail |+| (y.head :: y.tail))
}
Sukant Hajra / @shajra Validation with Functional Programming April 14, 2016 34 / 61
Non-empty List
Monad Instance
import scalaz.Monad
import scalaz.syntax.monad._
implicit val nelMonad: Monad[Nel] =
new Monad[Nel] {
def point[A](a: => A) = Nel(a, List.empty)
def bind[A, B](as: Nel[A])(f: A => Nel[B]) = {
val front = f(as.head)
Nel(
front.head,
front.tail |+| (as.tail >>= (f andThen { _.toList })))
}
}
Sukant Hajra / @shajra Validation with Functional Programming April 14, 2016 35 / 61
Non-empty List
Usage
scala> Nel.of(1,2,3) |+| Nel.of(4,5,6)
res2: nel.Nel[Int] = Nel(1, 2,3,4,5,6)
scala> Nel.of(1,2) >>= { x => Nel.of(x, x+10) }
res3: nel.Nel[Int] = Nel(1, 11,2,12)
scala> (Nel.of(1,2) |@| Nel.of(10,100)).apply { _ * _ }
res4: nel.Nel[Int] = Nel(10, 100,20,200)
Sukant Hajra / @shajra Validation with Functional Programming April 14, 2016 36 / 61
Disjunction
Definition
object disj {
sealed trait Disj[A, B] {
def fold[C](ifLeft: A => C)(ifRight: B => C) =
this match {
case LeftD(a) => ifLeft(a)
case RightD(b) => ifRight(b)
}
}
case class LeftD[A, B](a: A) extends Disj[A, B]
case class RightD[A, B](b: B) extends Disj[A, B]
}; import disj._
Sukant Hajra / @shajra Validation with Functional Programming April 14, 2016 37 / 61
Disjunction
Syntax
implicit class DisjOps[A](a: A) {
def left[B]: Disj[A, B] = LeftD(a)
def right[B]: Disj[B, A] = RightD(a)
}
Sukant Hajra / @shajra Validation with Functional Programming April 14, 2016 38 / 61
Disjunction
Instances
implicit def disjMonad[E]: Monad[Disj[E, ?]] =
new Monad[Disj[E, ?]] {
def point[A](a: => A) = a.right
def bind[A, B](d: Disj[E, A])(f: A => Disj[E, B]) =
d.fold { _.left[B] } { f(_) }
}
Sukant Hajra / @shajra Validation with Functional Programming April 14, 2016 39 / 61
Disjunction
Usage
scala> (1.right[String] |@| 2.right[String]).
| apply { _ + _ }
res5: disj.Disj[String,Int] = RightD(3)
scala> ("fail 1".left[Int] |@| "fail 2".left[Int]).
| apply { _ + _ }
res6: disj.Disj[String,Int] = LeftD(fail 1)
Sukant Hajra / @shajra Validation with Functional Programming April 14, 2016 40 / 61
Validation
Definition
object checked {
sealed trait Checked[A, B] {
def fold[C](ifFail: A => C)(ifPass: B => C) =
this match {
case Fail(a) => ifFail(a)
case Pass(b) => ifPass(b)
}
}
case class Fail[A, B](a: A) extends Checked[A, B]
case class Pass[A, B](b: B) extends Checked[A, B]
}; import checked._
Sukant Hajra / @shajra Validation with Functional Programming April 14, 2016 41 / 61
Validation
Syntax
implicit class CheckedOps1[A](a: A) {
def pass[B]: Checked[B, A] = Pass(a)
def fail[B]: Checked[A, B] = Fail(a)
def passNel[B]: Checked[Nel[B], A] = Pass(a)
def failNel[B]: Checked[Nel[A], B] = Fail(Nel of a)
}
Sukant Hajra / @shajra Validation with Functional Programming April 14, 2016 42 / 61
Validation
Instances
import scalaz.Applicative
implicit def checkedApplicative[E : Semigroup]
: Applicative[Checked[E, ?]] =
new Applicative[Checked[E, ?]] {
def point[A](a: => A) = a.pass[E]
def ap[A, B](c: => Checked[E, A])(f: => Checked[E, A=>B]) =
c.fold { e1 =>
f.fold(e2 => (e1 |+| e2).fail[B])(_ => e1.fail[B])
} { a =>
f.fold(_.fail[B])(_.apply(a).pass[E])
}
}
Sukant Hajra / @shajra Validation with Functional Programming April 14, 2016 43 / 61
Validation
Usage
scala> (1.passNel[String] |@| 2.passNel[String]).
| apply { _ + _ }
res8: checked.Checked[nel.Nel[String],Int] = Pass(3)
scala> ("fail 1".failNel[Int] |@| "fail 2".failNel[Int]).
| apply { _ + _ }
res9: checked.Checked[nel.Nel[String],Int] = Fail(Nel(fail 2,
fail 1))
Sukant Hajra / @shajra Validation with Functional Programming April 14, 2016 44 / 61
Read
Definition
case class Read[F[_], A, B](read: A => F[B])
Sukant Hajra / @shajra Validation with Functional Programming April 14, 2016 45 / 61
Read
Compose Instance
import scalaz.Compose
implicit def readCompose[F[_] : Monad]
: Compose[Read[F, ?, ?]] =
new Compose[Read[F, ?, ?]] {
def compose[A, B, C](f: Read[F, B, C], g: Read[F, A, B]) =
Read { a => g.read(a) >>= f.read }
}
Sukant Hajra / @shajra Validation with Functional Programming April 14, 2016 46 / 61
Read
Applicative Instance
implicit def readApplicative[F[_] : Applicative, A]
: Applicative[Read[F, A, ?]] =
new Applicative[Read[F, A, ?]] {
def point[B](b: => B) = Read { a => b.pure[F] }
def ap[B, C](r: => Read[F, A, B])(f: => Read[F, A, B=>C]) =
Read { a => (f.read(a) |@| r.read(a)) { _ apply _ } }
}
Sukant Hajra / @shajra Validation with Functional Programming April 14, 2016 47 / 61
ReadC
Definition
case class ReadC[A, E, B](read: A => Checked[E, B])
Sukant Hajra / @shajra Validation with Functional Programming April 14, 2016 48 / 61
ReadC
Instances
implicit def readCCompose[E]: Compose[ReadC[?, E, ?]] =
new Compose[ReadC[?, E, ?]] {
def compose[A, B, C]
(f: ReadC[B, E, C], g: ReadC[A, E, B]) =
ReadC { a => g.read(a).fold(_.fail[C])(f.read) }
}
implicit def readCApplicative[A, E : Semigroup]
: Applicative[ReadC[A, E, ?]] =
new Applicative[ReadC[A, E, ?]] {
def point[B](b: => B) =
ReadC { a => b.pure[Checked[E, ?]] }
def ap[B, C]
(r: => ReadC[A, E, B])(f: => ReadC[A, E, B=>C]) =
ReadC { a => (f.read(a) |@| r.read(a)) { _ apply _ } }
}
Sukant Hajra / @shajra Validation with Functional Programming April 14, 2016 49 / 61
Parsing Example
Sukant Hajra / @shajra Validation with Functional Programming April 14, 2016 50 / 61
Knobs library extension
Tracking path traversed
import scalaz.Show
import scalaz.std.string._
import scalaz.syntax.foldable._
case class Path(elems: List[String]) {
def -(elem: String) = new Path(elem.trim +: elems)
override def toString = elems.reverse intercalate "."
}
def emptyPath: Path = new Path(List.empty)
Sukant Hajra / @shajra Validation with Functional Programming April 14, 2016 51 / 61
Knobs library extension
Path-Config pair
import knobs.Config
case class Knobs(path: Path, config: Config) {
def -(elem: String): Knobs =
Knobs(path - elem, config subconfig elem)
}
def rootKnobs(config: Config): Knobs =
Knobs(emptyPath, config)
Sukant Hajra / @shajra Validation with Functional Programming April 14, 2016 52 / 61
Knobs library extension
Faults
import scala.reflect.runtime.universe.{ typeTag, TypeTag }
sealed abstract class ParseFault { def path: Path }
final case class KeyNotFound(path: Path) extends ParseFault
final case class WrongType(path: Path, typetag: TypeTag[_])
extends ParseFault
def keyNotFound(path: Path): ParseFault =
KeyNotFound(path)
def wrongType[A : TypeTag](path: Path): ParseFault =
WrongType(path, typeTag[A])
Sukant Hajra / @shajra Validation with Functional Programming April 14, 2016 53 / 61
Knobs library extension
Type alias
type Parse[A, B] = ReadC[A, Nel[ParseFault], B]
type KnobsRead[A] = Parse[Knobs, A]
Sukant Hajra / @shajra Validation with Functional Programming April 14, 2016 54 / 61
Knobs library extension
Read subconfig
def sub(path: String): KnobsRead[Knobs] =
ReadC { _ - path passNel }
Sukant Hajra / @shajra Validation with Functional Programming April 14, 2016 55 / 61
Knobs library extension
Lookup configuration
import knobs.{ CfgValue, Configured }
def required[A : Configured : TypeTag](path: String):
KnobsRead[A] =
ReadC { conf =>
val reportedPath = conf.path - path
conf.config
.lookup[CfgValue](path)
.fold(keyNotFound(reportedPath).fail[CfgValue])(_.pass)
.fold(_.failNel[A]) { v =>
v.convertTo[A]
.fold(wrongType[A](reportedPath).failNel[A])(_.passNel)
}
}
Sukant Hajra / @shajra Validation with Functional Programming April 14, 2016 56 / 61
Knobs library extension
Config reader
import scalaz.syntax.compose._
case class UserData(name: String, yearBorn: Int)
val userRead: KnobsRead[UserData] =
(required[String]("name") |@| required[Int]("year_born")).
apply(UserData)
def fullRead: KnobsRead[(UserData, UserData)] =
(userRead |@| (sub("nemesis") >>> userRead)).tupled
Sukant Hajra / @shajra Validation with Functional Programming April 14, 2016 57 / 61
Knobs library extension
Broken config example
val confText = """
name = "Donald Trump"
year_born = 1946
nemesis {
year_born = "Age of Enlightment"
name = 1650
}
"""
Sukant Hajra / @shajra Validation with Functional Programming April 14, 2016 58 / 61
Knobs library extension
Config reader
scala> Config.parse(confText).map { conf =>
| fullRead read rootKnobs(conf)
| }
res25:
scalaz./[Throwable,checked.Checked[nel.Nel[ParseFault],(UserD
UserData)]] =
/-(Fail(Nel(WrongType(nemesis.year_born,TypeTag[Int]),
WrongType(nemesis.name,TypeTag[String]))))
Sukant Hajra / @shajra Validation with Functional Programming April 14, 2016 59 / 61
Wrapping up
Sukant Hajra / @shajra Validation with Functional Programming April 14, 2016 60 / 61
This material
is compiler-checked (half-literate programming) using:
Rob Norris’s tut SBT plugin
pandoc
LATEX
Beamer
is at https://github.com/shajra/shajra-presentations.
Sukant Hajra / @shajra Validation with Functional Programming April 14, 2016 61 / 61

More Related Content

What's hot

Les03 (Using Single Row Functions To Customize Output)
Les03 (Using Single Row Functions To Customize Output)Les03 (Using Single Row Functions To Customize Output)
Les03 (Using Single Row Functions To Customize Output)
Achmad Solichin
 
Collections Framework Begineers guide 2
Collections Framework Begineers guide 2Collections Framework Begineers guide 2
Collections Framework Begineers guide 2
Kenji HASUNUMA
 
Single-Row Functions in orcale Data base
Single-Row Functions in orcale Data baseSingle-Row Functions in orcale Data base
Single-Row Functions in orcale Data base
Salman Memon
 
Best core & advanced java classes in mumbai
Best core & advanced java classes in mumbaiBest core & advanced java classes in mumbai
Best core & advanced java classes in mumbai
Vibrant Technologies & Computers
 
Aggregating Data Using Group Functions
Aggregating Data Using Group FunctionsAggregating Data Using Group Functions
Aggregating Data Using Group Functions
Salman Memon
 
Data type list_methods_in_python
Data type list_methods_in_pythonData type list_methods_in_python
Data type list_methods_in_python
deepalishinkar1
 
Sql subquery
Sql  subquerySql  subquery
Sql subquery
Raveena Thakur
 
Sub query_SQL
Sub query_SQLSub query_SQL
Sub query_SQL
CoT
 
Introduction to oracle functions
Introduction to oracle functionsIntroduction to oracle functions
Introduction to oracle functions
Nitesh Singh
 
Collections Java e Google Collections
Collections Java e Google CollectionsCollections Java e Google Collections
Collections Java e Google Collections
André Faria Gomes
 
Set methods in python
Set methods in pythonSet methods in python
Set methods in python
deepalishinkar1
 
Displaying Data from Multiple Tables - Oracle Data Base
Displaying Data from Multiple Tables - Oracle Data BaseDisplaying Data from Multiple Tables - Oracle Data Base
Displaying Data from Multiple Tables - Oracle Data Base
Salman Memon
 
An Introduction to Functional Programming - DeveloperUG - 20140311
An Introduction to Functional Programming - DeveloperUG - 20140311An Introduction to Functional Programming - DeveloperUG - 20140311
An Introduction to Functional Programming - DeveloperUG - 20140311
Andreas Pauley
 
Advanced plsql mock_assessment
Advanced plsql mock_assessmentAdvanced plsql mock_assessment
Advanced plsql mock_assessment
Saurabh K. Gupta
 
Analytic & Windowing functions in oracle
Analytic & Windowing functions in oracleAnalytic & Windowing functions in oracle
Analytic & Windowing functions in oracle
Logan Palanisamy
 
Functional Programming in Scala: Notes
Functional Programming in Scala: NotesFunctional Programming in Scala: Notes
Functional Programming in Scala: Notes
Roberto Casadei
 
R Programming Language
R Programming LanguageR Programming Language
R Programming Language
NareshKarela1
 
Collections in Java
Collections in JavaCollections in Java
Collections in Java
Khasim Cise
 
Entity Attribute Value (Eav)
Entity   Attribute   Value (Eav)Entity   Attribute   Value (Eav)
Entity Attribute Value (Eav)Tâm
 
java collections
java collectionsjava collections
java collections
javeed_mhd
 

What's hot (20)

Les03 (Using Single Row Functions To Customize Output)
Les03 (Using Single Row Functions To Customize Output)Les03 (Using Single Row Functions To Customize Output)
Les03 (Using Single Row Functions To Customize Output)
 
Collections Framework Begineers guide 2
Collections Framework Begineers guide 2Collections Framework Begineers guide 2
Collections Framework Begineers guide 2
 
Single-Row Functions in orcale Data base
Single-Row Functions in orcale Data baseSingle-Row Functions in orcale Data base
Single-Row Functions in orcale Data base
 
Best core & advanced java classes in mumbai
Best core & advanced java classes in mumbaiBest core & advanced java classes in mumbai
Best core & advanced java classes in mumbai
 
Aggregating Data Using Group Functions
Aggregating Data Using Group FunctionsAggregating Data Using Group Functions
Aggregating Data Using Group Functions
 
Data type list_methods_in_python
Data type list_methods_in_pythonData type list_methods_in_python
Data type list_methods_in_python
 
Sql subquery
Sql  subquerySql  subquery
Sql subquery
 
Sub query_SQL
Sub query_SQLSub query_SQL
Sub query_SQL
 
Introduction to oracle functions
Introduction to oracle functionsIntroduction to oracle functions
Introduction to oracle functions
 
Collections Java e Google Collections
Collections Java e Google CollectionsCollections Java e Google Collections
Collections Java e Google Collections
 
Set methods in python
Set methods in pythonSet methods in python
Set methods in python
 
Displaying Data from Multiple Tables - Oracle Data Base
Displaying Data from Multiple Tables - Oracle Data BaseDisplaying Data from Multiple Tables - Oracle Data Base
Displaying Data from Multiple Tables - Oracle Data Base
 
An Introduction to Functional Programming - DeveloperUG - 20140311
An Introduction to Functional Programming - DeveloperUG - 20140311An Introduction to Functional Programming - DeveloperUG - 20140311
An Introduction to Functional Programming - DeveloperUG - 20140311
 
Advanced plsql mock_assessment
Advanced plsql mock_assessmentAdvanced plsql mock_assessment
Advanced plsql mock_assessment
 
Analytic & Windowing functions in oracle
Analytic & Windowing functions in oracleAnalytic & Windowing functions in oracle
Analytic & Windowing functions in oracle
 
Functional Programming in Scala: Notes
Functional Programming in Scala: NotesFunctional Programming in Scala: Notes
Functional Programming in Scala: Notes
 
R Programming Language
R Programming LanguageR Programming Language
R Programming Language
 
Collections in Java
Collections in JavaCollections in Java
Collections in Java
 
Entity Attribute Value (Eav)
Entity   Attribute   Value (Eav)Entity   Attribute   Value (Eav)
Entity Attribute Value (Eav)
 
java collections
java collectionsjava collections
java collections
 

Similar to Scala Validation with Functional Programming

Functional Programming with JavaScript
Functional Programming with JavaScriptFunctional Programming with JavaScript
Functional Programming with JavaScript
WebF
 
Advance Scala - Oleg Mürk
Advance Scala - Oleg MürkAdvance Scala - Oleg Mürk
Advance Scala - Oleg Mürk
Planet OS
 
Practical cats
Practical catsPractical cats
Practical cats
Raymond Tay
 
Functions, Types, Programs and Effects
Functions, Types, Programs and EffectsFunctions, Types, Programs and Effects
Functions, Types, Programs and Effects
Raymond Roestenburg
 
Android best practices
Android best practicesAndroid best practices
Android best practices
Jose Manuel Ortega Candel
 
"Немного о функциональном программирование в JavaScript" Алексей Коваленко
"Немного о функциональном программирование в JavaScript" Алексей Коваленко"Немного о функциональном программирование в JavaScript" Алексей Коваленко
"Немного о функциональном программирование в JavaScript" Алексей Коваленко
Fwdays
 
Spark SQL Deep Dive @ Melbourne Spark Meetup
Spark SQL Deep Dive @ Melbourne Spark MeetupSpark SQL Deep Dive @ Melbourne Spark Meetup
Spark SQL Deep Dive @ Melbourne Spark Meetup
Databricks
 
SCALA - Functional domain
SCALA -  Functional domainSCALA -  Functional domain
SCALA - Functional domain
Bartosz Kosarzycki
 
Kpi driven-java-development
Kpi driven-java-developmentKpi driven-java-development
Kpi driven-java-development
Anirban Bhattacharjee
 
JavaCro'14 - Scala and Java EE 7 Development Experiences – Peter Pilgrim
JavaCro'14 - Scala and Java EE 7 Development Experiences – Peter PilgrimJavaCro'14 - Scala and Java EE 7 Development Experiences – Peter Pilgrim
JavaCro'14 - Scala and Java EE 7 Development Experiences – Peter Pilgrim
HUJAK - Hrvatska udruga Java korisnika / Croatian Java User Association
 
JavaCro 2014 Scala and Java EE 7 Development Experiences
JavaCro 2014 Scala and Java EE 7 Development ExperiencesJavaCro 2014 Scala and Java EE 7 Development Experiences
JavaCro 2014 Scala and Java EE 7 Development Experiences
Peter Pilgrim
 
Rntb20200805
Rntb20200805Rntb20200805
Rntb20200805
t k
 
JavaScript Editions ES7, ES8 and ES9 vs V8
JavaScript Editions ES7, ES8 and ES9 vs V8JavaScript Editions ES7, ES8 and ES9 vs V8
JavaScript Editions ES7, ES8 and ES9 vs V8
Rafael Casuso Romate
 
Procedure Typing for Scala
Procedure Typing for ScalaProcedure Typing for Scala
Procedure Typing for Scala
akuklev
 
Scala for Java programmers
Scala for Java programmersScala for Java programmers
Scala for Java programmers
輝 子安
 
Thinking Functionally with JavaScript
Thinking Functionally with JavaScriptThinking Functionally with JavaScript
Thinking Functionally with JavaScript
Luis Atencio
 
Spark workshop
Spark workshopSpark workshop
Spark workshop
Wojciech Pituła
 
Scala Functional Patterns
Scala Functional PatternsScala Functional Patterns
Scala Functional Patterns
league
 
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
Debasish Ghosh
 

Similar to Scala Validation with Functional Programming (20)

Functional Programming with JavaScript
Functional Programming with JavaScriptFunctional Programming with JavaScript
Functional Programming with JavaScript
 
Advance Scala - Oleg Mürk
Advance Scala - Oleg MürkAdvance Scala - Oleg Mürk
Advance Scala - Oleg Mürk
 
Practical cats
Practical catsPractical cats
Practical cats
 
Functions, Types, Programs and Effects
Functions, Types, Programs and EffectsFunctions, Types, Programs and Effects
Functions, Types, Programs and Effects
 
Android best practices
Android best practicesAndroid best practices
Android best practices
 
Scala ntnu
Scala ntnuScala ntnu
Scala ntnu
 
"Немного о функциональном программирование в JavaScript" Алексей Коваленко
"Немного о функциональном программирование в JavaScript" Алексей Коваленко"Немного о функциональном программирование в JavaScript" Алексей Коваленко
"Немного о функциональном программирование в JavaScript" Алексей Коваленко
 
Spark SQL Deep Dive @ Melbourne Spark Meetup
Spark SQL Deep Dive @ Melbourne Spark MeetupSpark SQL Deep Dive @ Melbourne Spark Meetup
Spark SQL Deep Dive @ Melbourne Spark Meetup
 
SCALA - Functional domain
SCALA -  Functional domainSCALA -  Functional domain
SCALA - Functional domain
 
Kpi driven-java-development
Kpi driven-java-developmentKpi driven-java-development
Kpi driven-java-development
 
JavaCro'14 - Scala and Java EE 7 Development Experiences – Peter Pilgrim
JavaCro'14 - Scala and Java EE 7 Development Experiences – Peter PilgrimJavaCro'14 - Scala and Java EE 7 Development Experiences – Peter Pilgrim
JavaCro'14 - Scala and Java EE 7 Development Experiences – Peter Pilgrim
 
JavaCro 2014 Scala and Java EE 7 Development Experiences
JavaCro 2014 Scala and Java EE 7 Development ExperiencesJavaCro 2014 Scala and Java EE 7 Development Experiences
JavaCro 2014 Scala and Java EE 7 Development Experiences
 
Rntb20200805
Rntb20200805Rntb20200805
Rntb20200805
 
JavaScript Editions ES7, ES8 and ES9 vs V8
JavaScript Editions ES7, ES8 and ES9 vs V8JavaScript Editions ES7, ES8 and ES9 vs V8
JavaScript Editions ES7, ES8 and ES9 vs V8
 
Procedure Typing for Scala
Procedure Typing for ScalaProcedure Typing for Scala
Procedure Typing for Scala
 
Scala for Java programmers
Scala for Java programmersScala for Java programmers
Scala for Java programmers
 
Thinking Functionally with JavaScript
Thinking Functionally with JavaScriptThinking Functionally with JavaScript
Thinking Functionally with JavaScript
 
Spark workshop
Spark workshopSpark workshop
Spark workshop
 
Scala Functional Patterns
Scala Functional PatternsScala Functional Patterns
Scala Functional Patterns
 
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
 

Recently uploaded

Sachpazis:Terzaghi Bearing Capacity Estimation in simple terms with Calculati...
Sachpazis:Terzaghi Bearing Capacity Estimation in simple terms with Calculati...Sachpazis:Terzaghi Bearing Capacity Estimation in simple terms with Calculati...
Sachpazis:Terzaghi Bearing Capacity Estimation in simple terms with Calculati...
Dr.Costas Sachpazis
 
Final project report on grocery store management system..pdf
Final project report on grocery store management system..pdfFinal project report on grocery store management system..pdf
Final project report on grocery store management system..pdf
Kamal Acharya
 
Water billing management system project report.pdf
Water billing management system project report.pdfWater billing management system project report.pdf
Water billing management system project report.pdf
Kamal Acharya
 
在线办理(ANU毕业证书)澳洲国立大学毕业证录取通知书一模一样
在线办理(ANU毕业证书)澳洲国立大学毕业证录取通知书一模一样在线办理(ANU毕业证书)澳洲国立大学毕业证录取通知书一模一样
在线办理(ANU毕业证书)澳洲国立大学毕业证录取通知书一模一样
obonagu
 
Cosmetic shop management system project report.pdf
Cosmetic shop management system project report.pdfCosmetic shop management system project report.pdf
Cosmetic shop management system project report.pdf
Kamal Acharya
 
Forklift Classes Overview by Intella Parts
Forklift Classes Overview by Intella PartsForklift Classes Overview by Intella Parts
Forklift Classes Overview by Intella Parts
Intella Parts
 
Literature Review Basics and Understanding Reference Management.pptx
Literature Review Basics and Understanding Reference Management.pptxLiterature Review Basics and Understanding Reference Management.pptx
Literature Review Basics and Understanding Reference Management.pptx
Dr Ramhari Poudyal
 
DfMAy 2024 - key insights and contributions
DfMAy 2024 - key insights and contributionsDfMAy 2024 - key insights and contributions
DfMAy 2024 - key insights and contributions
gestioneergodomus
 
Understanding Inductive Bias in Machine Learning
Understanding Inductive Bias in Machine LearningUnderstanding Inductive Bias in Machine Learning
Understanding Inductive Bias in Machine Learning
SUTEJAS
 
Design and Analysis of Algorithms-DP,Backtracking,Graphs,B&B
Design and Analysis of Algorithms-DP,Backtracking,Graphs,B&BDesign and Analysis of Algorithms-DP,Backtracking,Graphs,B&B
Design and Analysis of Algorithms-DP,Backtracking,Graphs,B&B
Sreedhar Chowdam
 
Industrial Training at Shahjalal Fertilizer Company Limited (SFCL)
Industrial Training at Shahjalal Fertilizer Company Limited (SFCL)Industrial Training at Shahjalal Fertilizer Company Limited (SFCL)
Industrial Training at Shahjalal Fertilizer Company Limited (SFCL)
MdTanvirMahtab2
 
Swimming pool mechanical components design.pptx
Swimming pool  mechanical components design.pptxSwimming pool  mechanical components design.pptx
Swimming pool mechanical components design.pptx
yokeleetan1
 
basic-wireline-operations-course-mahmoud-f-radwan.pdf
basic-wireline-operations-course-mahmoud-f-radwan.pdfbasic-wireline-operations-course-mahmoud-f-radwan.pdf
basic-wireline-operations-course-mahmoud-f-radwan.pdf
NidhalKahouli2
 
Harnessing WebAssembly for Real-time Stateless Streaming Pipelines
Harnessing WebAssembly for Real-time Stateless Streaming PipelinesHarnessing WebAssembly for Real-time Stateless Streaming Pipelines
Harnessing WebAssembly for Real-time Stateless Streaming Pipelines
Christina Lin
 
PPT on GRP pipes manufacturing and testing
PPT on GRP pipes manufacturing and testingPPT on GRP pipes manufacturing and testing
PPT on GRP pipes manufacturing and testing
anoopmanoharan2
 
Hybrid optimization of pumped hydro system and solar- Engr. Abdul-Azeez.pdf
Hybrid optimization of pumped hydro system and solar- Engr. Abdul-Azeez.pdfHybrid optimization of pumped hydro system and solar- Engr. Abdul-Azeez.pdf
Hybrid optimization of pumped hydro system and solar- Engr. Abdul-Azeez.pdf
fxintegritypublishin
 
一比一原版(UMich毕业证)密歇根大学|安娜堡分校毕业证成绩单专业办理
一比一原版(UMich毕业证)密歇根大学|安娜堡分校毕业证成绩单专业办理一比一原版(UMich毕业证)密歇根大学|安娜堡分校毕业证成绩单专业办理
一比一原版(UMich毕业证)密歇根大学|安娜堡分校毕业证成绩单专业办理
zwunae
 
digital fundamental by Thomas L.floydl.pdf
digital fundamental by Thomas L.floydl.pdfdigital fundamental by Thomas L.floydl.pdf
digital fundamental by Thomas L.floydl.pdf
drwaing
 
Fundamentals of Electric Drives and its applications.pptx
Fundamentals of Electric Drives and its applications.pptxFundamentals of Electric Drives and its applications.pptx
Fundamentals of Electric Drives and its applications.pptx
manasideore6
 
Governing Equations for Fundamental Aerodynamics_Anderson2010.pdf
Governing Equations for Fundamental Aerodynamics_Anderson2010.pdfGoverning Equations for Fundamental Aerodynamics_Anderson2010.pdf
Governing Equations for Fundamental Aerodynamics_Anderson2010.pdf
WENKENLI1
 

Recently uploaded (20)

Sachpazis:Terzaghi Bearing Capacity Estimation in simple terms with Calculati...
Sachpazis:Terzaghi Bearing Capacity Estimation in simple terms with Calculati...Sachpazis:Terzaghi Bearing Capacity Estimation in simple terms with Calculati...
Sachpazis:Terzaghi Bearing Capacity Estimation in simple terms with Calculati...
 
Final project report on grocery store management system..pdf
Final project report on grocery store management system..pdfFinal project report on grocery store management system..pdf
Final project report on grocery store management system..pdf
 
Water billing management system project report.pdf
Water billing management system project report.pdfWater billing management system project report.pdf
Water billing management system project report.pdf
 
在线办理(ANU毕业证书)澳洲国立大学毕业证录取通知书一模一样
在线办理(ANU毕业证书)澳洲国立大学毕业证录取通知书一模一样在线办理(ANU毕业证书)澳洲国立大学毕业证录取通知书一模一样
在线办理(ANU毕业证书)澳洲国立大学毕业证录取通知书一模一样
 
Cosmetic shop management system project report.pdf
Cosmetic shop management system project report.pdfCosmetic shop management system project report.pdf
Cosmetic shop management system project report.pdf
 
Forklift Classes Overview by Intella Parts
Forklift Classes Overview by Intella PartsForklift Classes Overview by Intella Parts
Forklift Classes Overview by Intella Parts
 
Literature Review Basics and Understanding Reference Management.pptx
Literature Review Basics and Understanding Reference Management.pptxLiterature Review Basics and Understanding Reference Management.pptx
Literature Review Basics and Understanding Reference Management.pptx
 
DfMAy 2024 - key insights and contributions
DfMAy 2024 - key insights and contributionsDfMAy 2024 - key insights and contributions
DfMAy 2024 - key insights and contributions
 
Understanding Inductive Bias in Machine Learning
Understanding Inductive Bias in Machine LearningUnderstanding Inductive Bias in Machine Learning
Understanding Inductive Bias in Machine Learning
 
Design and Analysis of Algorithms-DP,Backtracking,Graphs,B&B
Design and Analysis of Algorithms-DP,Backtracking,Graphs,B&BDesign and Analysis of Algorithms-DP,Backtracking,Graphs,B&B
Design and Analysis of Algorithms-DP,Backtracking,Graphs,B&B
 
Industrial Training at Shahjalal Fertilizer Company Limited (SFCL)
Industrial Training at Shahjalal Fertilizer Company Limited (SFCL)Industrial Training at Shahjalal Fertilizer Company Limited (SFCL)
Industrial Training at Shahjalal Fertilizer Company Limited (SFCL)
 
Swimming pool mechanical components design.pptx
Swimming pool  mechanical components design.pptxSwimming pool  mechanical components design.pptx
Swimming pool mechanical components design.pptx
 
basic-wireline-operations-course-mahmoud-f-radwan.pdf
basic-wireline-operations-course-mahmoud-f-radwan.pdfbasic-wireline-operations-course-mahmoud-f-radwan.pdf
basic-wireline-operations-course-mahmoud-f-radwan.pdf
 
Harnessing WebAssembly for Real-time Stateless Streaming Pipelines
Harnessing WebAssembly for Real-time Stateless Streaming PipelinesHarnessing WebAssembly for Real-time Stateless Streaming Pipelines
Harnessing WebAssembly for Real-time Stateless Streaming Pipelines
 
PPT on GRP pipes manufacturing and testing
PPT on GRP pipes manufacturing and testingPPT on GRP pipes manufacturing and testing
PPT on GRP pipes manufacturing and testing
 
Hybrid optimization of pumped hydro system and solar- Engr. Abdul-Azeez.pdf
Hybrid optimization of pumped hydro system and solar- Engr. Abdul-Azeez.pdfHybrid optimization of pumped hydro system and solar- Engr. Abdul-Azeez.pdf
Hybrid optimization of pumped hydro system and solar- Engr. Abdul-Azeez.pdf
 
一比一原版(UMich毕业证)密歇根大学|安娜堡分校毕业证成绩单专业办理
一比一原版(UMich毕业证)密歇根大学|安娜堡分校毕业证成绩单专业办理一比一原版(UMich毕业证)密歇根大学|安娜堡分校毕业证成绩单专业办理
一比一原版(UMich毕业证)密歇根大学|安娜堡分校毕业证成绩单专业办理
 
digital fundamental by Thomas L.floydl.pdf
digital fundamental by Thomas L.floydl.pdfdigital fundamental by Thomas L.floydl.pdf
digital fundamental by Thomas L.floydl.pdf
 
Fundamentals of Electric Drives and its applications.pptx
Fundamentals of Electric Drives and its applications.pptxFundamentals of Electric Drives and its applications.pptx
Fundamentals of Electric Drives and its applications.pptx
 
Governing Equations for Fundamental Aerodynamics_Anderson2010.pdf
Governing Equations for Fundamental Aerodynamics_Anderson2010.pdfGoverning Equations for Fundamental Aerodynamics_Anderson2010.pdf
Governing Equations for Fundamental Aerodynamics_Anderson2010.pdf
 

Scala Validation with Functional Programming

  • 1. Validation with Functional Programming Sukant Hajra / @shajra April 14, 2016 Sukant Hajra / @shajra Validation with Functional Programming April 14, 2016 1 / 61
  • 2. Some Goals explore data structures for managing errors use type classes to get nice APIs (DSLs) see some examples with parsing Sukant Hajra / @shajra Validation with Functional Programming April 14, 2016 2 / 61
  • 3. scalaz./ Construction scala> import scalaz.syntax.either._ import scalaz.syntax.either._ scala> 1.right[String] res0: scalaz./[String,Int] = /-(1) scala> "fail".left[Int] res1: scalaz./[String,Int] = -/(fail) Sukant Hajra / @shajra Validation with Functional Programming April 14, 2016 3 / 61
  • 4. scalaz./ Monadic Syntax scala> 1.right[String].flatMap { a => | 2.right[String].map { b => | a + b | } | } res2: scalaz./[String,Int] = /-(3) scala> for { | a <- 1.right[String] | b <- 2.right[String] | } yield a + b res3: scalaz./[String,Int] = /-(3) Sukant Hajra / @shajra Validation with Functional Programming April 14, 2016 4 / 61
  • 5. scalaz./ Applicative Syntax scala> import scalaz.syntax.apply._ import scalaz.syntax.apply._ scala> 1.right[String] |@| 2.right[String] apply { _ + _ } res4: scalaz./[String,Int] = /-(3) Sukant Hajra / @shajra Validation with Functional Programming April 14, 2016 5 / 61
  • 6. scalaz./ Semantics scala> (1.right[String] |@| 2.right[String]). | apply { _ + _ } res5: scalaz./[String,Int] = /-(3) scala> (1.right[String] |@| "fail 2".left[Int]). | apply { _ + _ } res6: scalaz./[String,Int] = -/(fail 2) scala> ("fail 1".left[Int] |@| 2.right[String]). | apply { _ + _ } res7: scalaz./[String,Int] = -/(fail 1) scala> ("fail 1".left[Int] |@| "fail 2".left[Int]). | apply { _ + _ } res8: scalaz./[String,Int] = -/(fail 1) Sukant Hajra / @shajra Validation with Functional Programming April 14, 2016 6 / 61
  • 7. scalaz.ValidationNel Construction scala> import scalaz.syntax.validation._ import scalaz.syntax.validation._ scala> 1.success[String] res9: scalaz.Validation[String,Int] = Success(1) scala> "fail".failure[Int] res10: scalaz.Validation[String,Int] = Failure(fail) scala> 1.successNel[String] res11: scalaz.ValidationNel[String,Int] = Success(1) scala> "fail".failureNel[Int] res12: scalaz.ValidationNel[String,Int] = Failure(NonEmptyList(fail)) Sukant Hajra / @shajra Validation with Functional Programming April 14, 2016 7 / 61
  • 8. scalaz.ValidationNel Semantics scala> (1.successNel[String] |@| 2.successNel[String]). | apply { _ + _ } res13: scalaz.Validation[scalaz.NonEmptyList[String],Int] = Success(3) scala> (1.successNel[String] |@| "fail 2".failureNel[Int]). | apply { _ + _ } res14: scalaz.Validation[scalaz.NonEmptyList[String],Int] = Failure(NonEmptyList(fail 2)) scala> ("fail 1".failureNel[Int] |@| "fail 2".failureNel[Int]). | apply { _ + _ } res15: scalaz.Validation[scalaz.NonEmptyList[String],Int] = Failure(NonEmptyList(fail 1, fail 2)) Sukant Hajra / @shajra Validation with Functional Programming April 14, 2016 8 / 61
  • 9. scalaz.ValidationNel Dangerous flatMap scala> "fail 1".failureNel[Int].flatMap { a => | "fail 2".failureNel[Int].map { b => | a + b | } | } warning: there was one deprecation warning; re-run with -deprecation for details res16: scalaz.Validation[scalaz.NonEmptyList[String],Int] = Failure(NonEmptyList(fail 1)) Sukant Hajra / @shajra Validation with Functional Programming April 14, 2016 9 / 61
  • 10. Composition Defining some functions import scalaz.std.function._ import scalaz.syntax.compose._ def add: Int => Int => Int = a => b => a + b val mult: Int => Int => Int = a => b => a * b Usage scala> add(2) >>> mult(10) >>> add(3) apply 0 res18: Int = 23 scala> add(2) <<< mult(10) <<< add(3) apply 0 res19: Int = 32 Sukant Hajra / @shajra Validation with Functional Programming April 14, 2016 10 / 61
  • 11. What more is possible? Consider this broken config val confText = """ name = "Donald Trump" year_born = 1946 nemesis { year_born = "Age of Enlightment" name = 1650 } """ Both nemesis.year_born and nemesis.name have the wrong type. Sukant Hajra / @shajra Validation with Functional Programming April 14, 2016 11 / 61
  • 12. What more is possible? Could we catch both defects with this API? case class UserData(name: String, yearBorn: Int) def sub(key: String): ConfRead[Json] = ??? def required[A : Readable](key: String): ConfRead[A] = ??? val userRead: ConfRead[UserData] = (required[String]("name") |@| required[Int]("year_born")). apply(UserData) def fullRead: ConfRead[(UserData, UserData)] = (userRead |@| (sub("nemesis") >>> userRead)).tupled Config.parse map fullRead.read Sukant Hajra / @shajra Validation with Functional Programming April 14, 2016 12 / 61
  • 13. Type Classes (a review) Sukant Hajra / @shajra Validation with Functional Programming April 14, 2016 13 / 61
  • 14. Useful type classes We’ll quickly review: Semigroup Compose Covariant Functor Applicative Functor Monad Also useful, but not discussed today: Profunctor Arrow or Strong Profunctor Sukant Hajra / @shajra Validation with Functional Programming April 14, 2016 14 / 61
  • 15. High quality type classes Type classes are statically dispatched interfaces that should be implementable for many data types provide functions that lead to rich libraries have only one instance per type (global uniqueness) 1 have laws (strong contracts). Auto-deriving instances is also nice. 1 Global uniqueness is debated by a few Sukant Hajra / @shajra Validation with Functional Programming April 14, 2016 15 / 61
  • 16. Semigroup Definition trait Semigroup[A] { def append(x: A, y: A): A } object Semigroup { def apply[A](implicit ev: Semigroup[A]): Semigroup[A] = ev } Sukant Hajra / @shajra Validation with Functional Programming April 14, 2016 16 / 61
  • 17. Semigroup Laws trait SemigroupLaws[A] extends Semigroup[A] { def semigroupAssociativity(x: A, y: A, z: A) = append(x, append(y, z)) == append(append(x, y), z) } Sukant Hajra / @shajra Validation with Functional Programming April 14, 2016 17 / 61
  • 18. Semigroup Syntax implicit class SemigroupOps[A : Semigroup](a1: A) { def |+|(a2: A): A = Semigroup[A].append(a1, a2) } Sukant Hajra / @shajra Validation with Functional Programming April 14, 2016 18 / 61
  • 19. Compose Definition trait Compose[F[_, _]] { def compose[A, B, C](fbc: F[B, C], fab: F[A, B]): F[A, C] } object Compose { def apply[F[_, _]](implicit ev: Compose[F]): Compose[F] = ev } Sukant Hajra / @shajra Validation with Functional Programming April 14, 2016 19 / 61
  • 20. Compose Laws trait ComposeLaws[F[_, _]] extends Compose[F] { def composeAssociativity[A, B, C, D] (fab: F[A, B], fbc: F[B, C], fcd: F[C, D]) = compose(fcd, compose(fbc, fab)) == compose(compose(fcd, fbc), fab) } Sukant Hajra / @shajra Validation with Functional Programming April 14, 2016 20 / 61
  • 21. Compose Syntax implicit class ComposeOps[F[_, _], A, B](f1: F[A, B])( implicit ev: Compose[F]) { def <<<[C](f2: F[C, A]): F[C, B] = Compose[F].compose(f1, f2) def >>>[C](f2: F[B, C]): F[A, C] = Compose[F].compose(f2, f1) } Sukant Hajra / @shajra Validation with Functional Programming April 14, 2016 21 / 61
  • 22. (Covariant) Functor Definition trait Functor[F[_]] { def map[A, B](fa: F[A])(f: A => B): F[B] } object Functor { def apply[F[_]](implicit ev: Functor[F]): Functor[F] = ev } Sukant Hajra / @shajra Validation with Functional Programming April 14, 2016 22 / 61
  • 23. (Covariant) Functor Laws trait FunctorLaws[F[_]] extends Functor[F] { def functorIdentity[A](fa: F[A]) = map(fa)(identity[A]) == fa def functorComposition[A, B, C] (fa: F[A], f: A => B, g: B => C) = map(map(fa)(f))(g) == map(fa)(f andThen g) } Sukant Hajra / @shajra Validation with Functional Programming April 14, 2016 23 / 61
  • 24. Functor Syntax implicit class FunctorOps[F[_] : Functor, A](fa: F[A]) { def map[B](f: A => B): F[B] = Functor[F].map(fa)(f) def fpair: F[(A, A)] = map { a => (a, a) } def fproduct[B](f: A => B): F[(A, B)] = map { a => (a, f(a)) } } Sukant Hajra / @shajra Validation with Functional Programming April 14, 2016 24 / 61
  • 25. Applicative (Functor) Definition trait Applicative[F[_]] extends Functor[F] { def pure[A](a: A): F[A] def ap[A, B](fa: F[A])(fab: F[A => B]): F[B] } object Applicative { def apply[F[_]](implicit ev: Applicative[F]) : Applicative[F] = ev } Sukant Hajra / @shajra Validation with Functional Programming April 14, 2016 25 / 61
  • 26. Applicative (Functor) Laws trait ApplicativeLaws1[F[_]] extends Applicative[F] with FunctorLaws[F] { def applicativeIdentity[A](fa: F[A]) = ap(fa)(pure[A => A](identity)) == fa def applicativeHomomorphism[A, B](a: A, ab: A => B) = ap(pure(a))(pure(ab)) == pure(ab(a)) def applicativeInterchange[A, B](a: A, f: F[A => B]) = ap(pure(a))(f) == ap(f)(pure { (ff: A => B) => ff(a) }) } Sukant Hajra / @shajra Validation with Functional Programming April 14, 2016 26 / 61
  • 27. Applicative (Functor) Laws trait ApplicativeLaws2[F[_]] extends ApplicativeLaws1[F] { def applicativeDerivedMap[A, B](f: A => B, fa: F[A]) = map(fa)(f) == ap(fa)(pure(f)) def applicativeComposition[A, B, C] (fa: F[A], fab: F[A => B], fbc: F[B => C]) = ap(ap(fa)(fab))(fbc) == ap(fa)( ap(fab)( map[B=>C, (A=>B)=>(A=>C)](fbc) { bc => ab => bc compose ab })) } Sukant Hajra / @shajra Validation with Functional Programming April 14, 2016 27 / 61
  • 28. Applicative (Functor) Syntax implicit class ApplicativeOps1[F[_] : Applicative, A]( fa: F[A]) { def <*>[A, B](f: F[A => B]) = Applicative[F].ap(fa)(f) def *>[B](fb: F[B]): F[B] = Applicative[F].ap(fa)(Functor[F].map(fb)(Function.const)) def <*[B](fb: F[B]): F[A] = Applicative[F].ap(fb)(fa map Function.const) } implicit class ApplicativeOps2[A](a: A) { def pure[F[_] : Applicative]: F[A] = Applicative[F].pure(a) } Sukant Hajra / @shajra Validation with Functional Programming April 14, 2016 28 / 61
  • 29. Monad Definition trait Monad[F[_]] extends Applicative[F] { def bind[A, B](fa: F[A])(fab: A => F[B]): F[B] } object Monad { def apply[F[_]](implicit ev: Monad[F]): Monad[F] = ev } Sukant Hajra / @shajra Validation with Functional Programming April 14, 2016 29 / 61
  • 30. Monad Laws trait MonadLaws[F[_]] extends Monad[F] { def monadRightIdentity[A](fa: F[A]) = bind(fa)(pure) == fa def monadLeftIdentity[A, B](a: A, f: A => F[B]) = bind(pure(a))(f) == f(a) def monadAssociativity[A, B, C] (fa: F[A], f: A => F[B], g: B => F[C]) = bind(bind(fa)(f))(g) == bind(fa) { a => bind(f(a))(g) } def monadDerivedAp[A, B](fab: F[A => B], fa: F[A]) = bind(fa) { a => map(fab) { f => f(a) } } == ap(fa)(fab) } Sukant Hajra / @shajra Validation with Functional Programming April 14, 2016 30 / 61
  • 31. Monad Syntax implicit class MonadOps[F[_] : Monad, A](fa: F[A]) { def flatMap[B](f: A => F[B]): F[B] = Monad[F].bind(fa)(f) def >>=[B](f: A => F[B]): F[B] = flatMap(f) def >>![B](f: A => F[B]): F[A] = flatMap { a => Monad[F].map(f(a)) { b => a } } def >>[B](fb: F[B]): F[B] = flatMap(Function.const(fb)) import scalaz.Leibniz.=== def join[B](implicit ev: A === F[B]): F[B] = Monad[F].bind(ev.subst[F](fa))(identity) } Sukant Hajra / @shajra Validation with Functional Programming April 14, 2016 31 / 61
  • 32. Data types Sukant Hajra / @shajra Validation with Functional Programming April 14, 2016 32 / 61
  • 33. Non-empty List Definition object nel { case class Nel[A](head: A, tail: List[A]) { def toList: List[A] = head :: tail override def toString: String = s"""Nel(${head}, ${tail mkString ","})""" } object Nel { def of[A](head: A, tail: A*): Nel[A] = new Nel(head, tail.toList) } }; import nel._ Sukant Hajra / @shajra Validation with Functional Programming April 14, 2016 33 / 61
  • 34. Non-empty List Semigroup Instance import scalaz.Semigroup import scalaz.std.list._ import scalaz.syntax.semigroup._ implicit def nelSemigroup[A]: Semigroup[Nel[A]] = new Semigroup[Nel[A]] { def append(x: Nel[A], y: => Nel[A]) = Nel[A](x.head, x.tail |+| (y.head :: y.tail)) } Sukant Hajra / @shajra Validation with Functional Programming April 14, 2016 34 / 61
  • 35. Non-empty List Monad Instance import scalaz.Monad import scalaz.syntax.monad._ implicit val nelMonad: Monad[Nel] = new Monad[Nel] { def point[A](a: => A) = Nel(a, List.empty) def bind[A, B](as: Nel[A])(f: A => Nel[B]) = { val front = f(as.head) Nel( front.head, front.tail |+| (as.tail >>= (f andThen { _.toList }))) } } Sukant Hajra / @shajra Validation with Functional Programming April 14, 2016 35 / 61
  • 36. Non-empty List Usage scala> Nel.of(1,2,3) |+| Nel.of(4,5,6) res2: nel.Nel[Int] = Nel(1, 2,3,4,5,6) scala> Nel.of(1,2) >>= { x => Nel.of(x, x+10) } res3: nel.Nel[Int] = Nel(1, 11,2,12) scala> (Nel.of(1,2) |@| Nel.of(10,100)).apply { _ * _ } res4: nel.Nel[Int] = Nel(10, 100,20,200) Sukant Hajra / @shajra Validation with Functional Programming April 14, 2016 36 / 61
  • 37. Disjunction Definition object disj { sealed trait Disj[A, B] { def fold[C](ifLeft: A => C)(ifRight: B => C) = this match { case LeftD(a) => ifLeft(a) case RightD(b) => ifRight(b) } } case class LeftD[A, B](a: A) extends Disj[A, B] case class RightD[A, B](b: B) extends Disj[A, B] }; import disj._ Sukant Hajra / @shajra Validation with Functional Programming April 14, 2016 37 / 61
  • 38. Disjunction Syntax implicit class DisjOps[A](a: A) { def left[B]: Disj[A, B] = LeftD(a) def right[B]: Disj[B, A] = RightD(a) } Sukant Hajra / @shajra Validation with Functional Programming April 14, 2016 38 / 61
  • 39. Disjunction Instances implicit def disjMonad[E]: Monad[Disj[E, ?]] = new Monad[Disj[E, ?]] { def point[A](a: => A) = a.right def bind[A, B](d: Disj[E, A])(f: A => Disj[E, B]) = d.fold { _.left[B] } { f(_) } } Sukant Hajra / @shajra Validation with Functional Programming April 14, 2016 39 / 61
  • 40. Disjunction Usage scala> (1.right[String] |@| 2.right[String]). | apply { _ + _ } res5: disj.Disj[String,Int] = RightD(3) scala> ("fail 1".left[Int] |@| "fail 2".left[Int]). | apply { _ + _ } res6: disj.Disj[String,Int] = LeftD(fail 1) Sukant Hajra / @shajra Validation with Functional Programming April 14, 2016 40 / 61
  • 41. Validation Definition object checked { sealed trait Checked[A, B] { def fold[C](ifFail: A => C)(ifPass: B => C) = this match { case Fail(a) => ifFail(a) case Pass(b) => ifPass(b) } } case class Fail[A, B](a: A) extends Checked[A, B] case class Pass[A, B](b: B) extends Checked[A, B] }; import checked._ Sukant Hajra / @shajra Validation with Functional Programming April 14, 2016 41 / 61
  • 42. Validation Syntax implicit class CheckedOps1[A](a: A) { def pass[B]: Checked[B, A] = Pass(a) def fail[B]: Checked[A, B] = Fail(a) def passNel[B]: Checked[Nel[B], A] = Pass(a) def failNel[B]: Checked[Nel[A], B] = Fail(Nel of a) } Sukant Hajra / @shajra Validation with Functional Programming April 14, 2016 42 / 61
  • 43. Validation Instances import scalaz.Applicative implicit def checkedApplicative[E : Semigroup] : Applicative[Checked[E, ?]] = new Applicative[Checked[E, ?]] { def point[A](a: => A) = a.pass[E] def ap[A, B](c: => Checked[E, A])(f: => Checked[E, A=>B]) = c.fold { e1 => f.fold(e2 => (e1 |+| e2).fail[B])(_ => e1.fail[B]) } { a => f.fold(_.fail[B])(_.apply(a).pass[E]) } } Sukant Hajra / @shajra Validation with Functional Programming April 14, 2016 43 / 61
  • 44. Validation Usage scala> (1.passNel[String] |@| 2.passNel[String]). | apply { _ + _ } res8: checked.Checked[nel.Nel[String],Int] = Pass(3) scala> ("fail 1".failNel[Int] |@| "fail 2".failNel[Int]). | apply { _ + _ } res9: checked.Checked[nel.Nel[String],Int] = Fail(Nel(fail 2, fail 1)) Sukant Hajra / @shajra Validation with Functional Programming April 14, 2016 44 / 61
  • 45. Read Definition case class Read[F[_], A, B](read: A => F[B]) Sukant Hajra / @shajra Validation with Functional Programming April 14, 2016 45 / 61
  • 46. Read Compose Instance import scalaz.Compose implicit def readCompose[F[_] : Monad] : Compose[Read[F, ?, ?]] = new Compose[Read[F, ?, ?]] { def compose[A, B, C](f: Read[F, B, C], g: Read[F, A, B]) = Read { a => g.read(a) >>= f.read } } Sukant Hajra / @shajra Validation with Functional Programming April 14, 2016 46 / 61
  • 47. Read Applicative Instance implicit def readApplicative[F[_] : Applicative, A] : Applicative[Read[F, A, ?]] = new Applicative[Read[F, A, ?]] { def point[B](b: => B) = Read { a => b.pure[F] } def ap[B, C](r: => Read[F, A, B])(f: => Read[F, A, B=>C]) = Read { a => (f.read(a) |@| r.read(a)) { _ apply _ } } } Sukant Hajra / @shajra Validation with Functional Programming April 14, 2016 47 / 61
  • 48. ReadC Definition case class ReadC[A, E, B](read: A => Checked[E, B]) Sukant Hajra / @shajra Validation with Functional Programming April 14, 2016 48 / 61
  • 49. ReadC Instances implicit def readCCompose[E]: Compose[ReadC[?, E, ?]] = new Compose[ReadC[?, E, ?]] { def compose[A, B, C] (f: ReadC[B, E, C], g: ReadC[A, E, B]) = ReadC { a => g.read(a).fold(_.fail[C])(f.read) } } implicit def readCApplicative[A, E : Semigroup] : Applicative[ReadC[A, E, ?]] = new Applicative[ReadC[A, E, ?]] { def point[B](b: => B) = ReadC { a => b.pure[Checked[E, ?]] } def ap[B, C] (r: => ReadC[A, E, B])(f: => ReadC[A, E, B=>C]) = ReadC { a => (f.read(a) |@| r.read(a)) { _ apply _ } } } Sukant Hajra / @shajra Validation with Functional Programming April 14, 2016 49 / 61
  • 50. Parsing Example Sukant Hajra / @shajra Validation with Functional Programming April 14, 2016 50 / 61
  • 51. Knobs library extension Tracking path traversed import scalaz.Show import scalaz.std.string._ import scalaz.syntax.foldable._ case class Path(elems: List[String]) { def -(elem: String) = new Path(elem.trim +: elems) override def toString = elems.reverse intercalate "." } def emptyPath: Path = new Path(List.empty) Sukant Hajra / @shajra Validation with Functional Programming April 14, 2016 51 / 61
  • 52. Knobs library extension Path-Config pair import knobs.Config case class Knobs(path: Path, config: Config) { def -(elem: String): Knobs = Knobs(path - elem, config subconfig elem) } def rootKnobs(config: Config): Knobs = Knobs(emptyPath, config) Sukant Hajra / @shajra Validation with Functional Programming April 14, 2016 52 / 61
  • 53. Knobs library extension Faults import scala.reflect.runtime.universe.{ typeTag, TypeTag } sealed abstract class ParseFault { def path: Path } final case class KeyNotFound(path: Path) extends ParseFault final case class WrongType(path: Path, typetag: TypeTag[_]) extends ParseFault def keyNotFound(path: Path): ParseFault = KeyNotFound(path) def wrongType[A : TypeTag](path: Path): ParseFault = WrongType(path, typeTag[A]) Sukant Hajra / @shajra Validation with Functional Programming April 14, 2016 53 / 61
  • 54. Knobs library extension Type alias type Parse[A, B] = ReadC[A, Nel[ParseFault], B] type KnobsRead[A] = Parse[Knobs, A] Sukant Hajra / @shajra Validation with Functional Programming April 14, 2016 54 / 61
  • 55. Knobs library extension Read subconfig def sub(path: String): KnobsRead[Knobs] = ReadC { _ - path passNel } Sukant Hajra / @shajra Validation with Functional Programming April 14, 2016 55 / 61
  • 56. Knobs library extension Lookup configuration import knobs.{ CfgValue, Configured } def required[A : Configured : TypeTag](path: String): KnobsRead[A] = ReadC { conf => val reportedPath = conf.path - path conf.config .lookup[CfgValue](path) .fold(keyNotFound(reportedPath).fail[CfgValue])(_.pass) .fold(_.failNel[A]) { v => v.convertTo[A] .fold(wrongType[A](reportedPath).failNel[A])(_.passNel) } } Sukant Hajra / @shajra Validation with Functional Programming April 14, 2016 56 / 61
  • 57. Knobs library extension Config reader import scalaz.syntax.compose._ case class UserData(name: String, yearBorn: Int) val userRead: KnobsRead[UserData] = (required[String]("name") |@| required[Int]("year_born")). apply(UserData) def fullRead: KnobsRead[(UserData, UserData)] = (userRead |@| (sub("nemesis") >>> userRead)).tupled Sukant Hajra / @shajra Validation with Functional Programming April 14, 2016 57 / 61
  • 58. Knobs library extension Broken config example val confText = """ name = "Donald Trump" year_born = 1946 nemesis { year_born = "Age of Enlightment" name = 1650 } """ Sukant Hajra / @shajra Validation with Functional Programming April 14, 2016 58 / 61
  • 59. Knobs library extension Config reader scala> Config.parse(confText).map { conf => | fullRead read rootKnobs(conf) | } res25: scalaz./[Throwable,checked.Checked[nel.Nel[ParseFault],(UserD UserData)]] = /-(Fail(Nel(WrongType(nemesis.year_born,TypeTag[Int]), WrongType(nemesis.name,TypeTag[String])))) Sukant Hajra / @shajra Validation with Functional Programming April 14, 2016 59 / 61
  • 60. Wrapping up Sukant Hajra / @shajra Validation with Functional Programming April 14, 2016 60 / 61
  • 61. This material is compiler-checked (half-literate programming) using: Rob Norris’s tut SBT plugin pandoc LATEX Beamer is at https://github.com/shajra/shajra-presentations. Sukant Hajra / @shajra Validation with Functional Programming April 14, 2016 61 / 61