├── .gitignore ├── README.md ├── applicative └── src │ └── main │ └── scala │ └── Applicative.scala ├── build.sbt ├── functor └── src │ └── main │ └── scala │ └── FoldMapable.scala ├── monad └── src │ └── main │ └── scala │ ├── EitherExample.scala │ ├── ErrorHandling.scala │ ├── MonadExamples.scala │ ├── Reader.scala │ ├── Writer.scala │ └── parallel │ └── FoldMap.scala ├── monadTransformer └── src │ └── main │ └── scala │ ├── FutureLogResult.scala │ └── OptionalResult.scala ├── monoid └── src │ └── main │ └── scala │ ├── FoldMap.scala │ ├── InstanceSelection.scala │ ├── MonoidExamples.scala │ ├── SuperAdder.scala │ └── parallel │ └── FoldMap.scala ├── probability └── src │ └── main │ └── scala │ └── probability │ ├── Continuous.scala │ ├── Discrete.scala │ ├── Enumeration.scala │ └── package.scala └── validation └── src ├── main └── scala │ └── validation │ ├── Check.scala │ ├── CheckF.scala │ ├── Example.scala │ └── Predicate.scala └── test └── scala └── validation ├── CheckSpec.scala └── PredicateSpec.scala /.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | project/target -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Code examples for Underscore's Advanced Scala with Scalaz course. See [Underscore.io](http://underscore.io/training/courses/advanced-scala-scalaz/) for more detail. 2 | -------------------------------------------------------------------------------- /applicative/src/main/scala/Applicative.scala: -------------------------------------------------------------------------------- 1 | import scalaz.Applicative 2 | import scalaz.std.option._ 3 | import scalaz.syntax.applicative._ 4 | 5 | object ApplicativeExample { 6 | some(1) <*> some((x: Int) => x + 1) 7 | some(1) <*> (some(2) <*> some((x: Int) => (y: Int) => x + y)) 8 | 9 | (some(1) |@| some(2)){ _ + _ } 10 | } 11 | -------------------------------------------------------------------------------- /build.sbt: -------------------------------------------------------------------------------- 1 | val scalaz = "org.scalaz" %% "scalaz-core" % "7.1.0" 2 | val scalazConcurrent = "org.scalaz" %% "scalaz-concurrent" % "7.1.0" 3 | val cats = "org.typelevel" %% "cats" % "0.6.0" 4 | val scalaTest = "org.scalatest" %% "scalatest" % "2.2.4" % "test" 5 | 6 | val settings = Seq( 7 | scalaVersion := "2.11.8", 8 | scalacOptions ++= Seq("-feature"), 9 | libraryDependencies ++= Seq(scalaz, scalazConcurrent, cats, scalaTest), 10 | resolvers ++= Seq(Resolver.sonatypeRepo("snapshots"), Resolver.sonatypeRepo("releases")), 11 | addCompilerPlugin("org.spire-math" %% "kind-projector" % "0.8.0") 12 | ) 13 | 14 | // Examples 15 | lazy val monoid = project.settings(settings:_*) 16 | lazy val functor = project.settings(settings:_*) 17 | lazy val monad = project.settings(settings:_*) 18 | lazy val monadTransformer = project.settings(settings:_*) 19 | lazy val applicative = project.settings(settings:_*) 20 | lazy val pygmyHadoop = project.settings(settings:_*) 21 | lazy val free = project.settings(settings:_*) 22 | 23 | // Projects 24 | lazy val validation = project.settings(settings:_*) 25 | lazy val probability = project.settings(settings:_*) 26 | -------------------------------------------------------------------------------- /functor/src/main/scala/FoldMapable.scala: -------------------------------------------------------------------------------- 1 | import scala.language.higherKinds 2 | 3 | import scalaz.Monoid 4 | import scalaz.syntax.monoid._ 5 | 6 | trait FoldMapable[F[_]] { 7 | def foldMap[A, B : Monoid](fa: F[A])(f: A => B): B 8 | } 9 | 10 | object FoldMapable { 11 | def apply[F[_] : FoldMapable]: FoldMapable[F] = 12 | implicitly[FoldMapable[F]] 13 | 14 | implicit object ListFoldMapable extends FoldMapable[List] { 15 | def foldMap[A, B : Monoid](fa: List[A])(f: A => B): B = 16 | fa.foldLeft(mzero[B]){ _ |+| f(_) } 17 | } 18 | } 19 | 20 | object FoldMapableSyntax { 21 | implicit class IsFoldMapable[F[_] : FoldMapable, A](fa: F[A]) { 22 | def foldMap[B : Monoid](f: A => B): B = 23 | FoldMapable[F].foldMap(fa)(f) 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /monad/src/main/scala/EitherExample.scala: -------------------------------------------------------------------------------- 1 | import scalaz.\/ 2 | import scalaz.syntax.monad._ 3 | import scalaz.syntax.either._ 4 | 5 | object EitherExample { 6 | 7 | def flatMap = 8 | for { 9 | x <- 1.right[String] 10 | y <- (x + 2).right[String] 11 | } yield y * 3 12 | 13 | def basicMethods = { 14 | 1.right[String].fold( 15 | l = l => "We failed :(", 16 | r = r => s"We succeeded with $r" 17 | ) 18 | 1.right[String].getOrElse(0) 19 | 20 | 1.right[String] orElse 2.right[String] 21 | "Error".left[Int] orElse 2.right[String] 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /monad/src/main/scala/ErrorHandling.scala: -------------------------------------------------------------------------------- 1 | import scala.language.higherKinds 2 | 3 | import scalaz.{Id, Monoid, Monad, MonadPlus, \/} 4 | import scalaz.Id._ 5 | import scalaz.std.option._ 6 | import scalaz.syntax.monoid._ 7 | import scalaz.syntax.either._ 8 | import scalaz.syntax.monadPlus._ 9 | 10 | object MonadPlusExamples { 11 | some(3) <+> some(1) 12 | some(3) <+> none[Int] 13 | none[Int] <+> some(3) 14 | } 15 | 16 | object RecoveringFoldMap { 17 | def foldMapM[A, M[_] : MonadPlus, B: Monoid](iter: Iterable[A])(f: A => M[B] = (a: A) => a.point[Id]): M[B] = 18 | iter.foldLeft(mzero[B].point[M]){ (accum, elt) => 19 | for { 20 | a <- accum 21 | b <- f(elt) <+> mzero[B].point[M] 22 | } yield a |+| b 23 | } 24 | 25 | implicit class IterableFoldMappable[A](iter: Iterable[A]) { 26 | def foldMapM[M[_] : MonadPlus, B : Monoid](f: A => M[B] = (a: A) => a.point[Id]): M[B] = 27 | RecoveringFoldMap.foldMapM(iter)(f) 28 | } 29 | } 30 | 31 | object RecoveringExamples { 32 | import RecoveringFoldMap._ 33 | import scala.concurrent.ExecutionContext.Implicits.global 34 | 35 | def examples = { 36 | import scalaz.std.anyVal._ 37 | import scalaz.std.option._ 38 | 39 | Seq(1, 2, 3).foldMapM(a => if(a % 2 == 0) some(a) else none[Int]) 40 | } 41 | } 42 | 43 | object RecoveringToolkit { 44 | def foldMapM[A, M[_] : Monad, B: Monoid](iter: Iterable[A])(f: A => M[B] = (a: A) => a.point[Id]): M[B] = 45 | iter.foldLeft(mzero[B].point[M]){ (accum, elt) => 46 | for { 47 | a <- accum 48 | b <- f(elt) 49 | } yield a |+| b 50 | } 51 | 52 | implicit class IterableFoldMappable[A](iter: Iterable[A]) { 53 | def foldMapM[M[_] : Monad, B : Monoid](f: A => M[B] = (a: A) => a.point[Id]): M[B] = 54 | RecoveringToolkit.foldMapM(iter)(f) 55 | } 56 | 57 | def recover[A, M[_] : MonadPlus, B : Monoid](f: A => M[B]): (A => M[B]) = { 58 | val identity = mzero[B].point[M] 59 | a => (f(a) <+> identity) 60 | } 61 | 62 | def example = { 63 | import scalaz.std.anyVal._ 64 | import scalaz.std.option._ 65 | import scalaz.syntax.std.string._ 66 | 67 | Seq("1", "b", "3").foldMapM(recover(_.parseInt.toOption)) 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /monad/src/main/scala/MonadExamples.scala: -------------------------------------------------------------------------------- 1 | import scalaz.Monad 2 | import scalaz.std.option._ 3 | import scalaz.std.list._ 4 | import scalaz.syntax.monad._ 5 | 6 | object SyntaxExamples { 7 | val option = 3.point[Option] 8 | val f = ((x: Int) => x + 1).lift(Monad[Option]) 9 | 10 | f(option) 11 | option >>= ((x: Int) => (x + 39).point[Option]) 12 | option >> (42.point[Option]) 13 | } 14 | 15 | object InterfaceExamples { 16 | val option = Monad[Option].point(3) 17 | val f = Monad[Option].lift((x: Int) => x + 1) 18 | val tupled: Option[(Int, String, Double)] = 19 | Monad[Option].tuple3(some(1), some("hi"), some(3.0)) 20 | val sequence: Option[List[Int]] = 21 | Monad[Option].sequence(List(some(1), some(2), some(3))) 22 | 23 | f(option) 24 | } 25 | -------------------------------------------------------------------------------- /monad/src/main/scala/Reader.scala: -------------------------------------------------------------------------------- 1 | import scalaz.{Reader, Monad} 2 | import scalaz.std.function._ 3 | 4 | object MonadReaderExample { 5 | type Id = Int 6 | final case class User(name: String) 7 | final case class Db() { 8 | def getUser(userId: Id) = 9 | User("John Doe") 10 | def writeUser(user: User) = () 11 | } 12 | 13 | final case class Config(db: Db) 14 | type Env[A] = Reader[Config, A] 15 | 16 | def getUser(userId: Id): Env[User] = 17 | Reader(c => c.db.getUser(userId)) 18 | 19 | def writeUser(user: User): Env[Unit] = 20 | Reader(c => c.db.writeUser(user)) 21 | 22 | for { 23 | user <- getUser(1) 24 | _ <- writeUser(user) 25 | } yield () 26 | } 27 | -------------------------------------------------------------------------------- /monad/src/main/scala/Writer.scala: -------------------------------------------------------------------------------- 1 | import scalaz.Writer 2 | import scalaz.syntax.writer._ 3 | import scalaz.std.vector._ 4 | 5 | object WriterExamples { 6 | def example = { 7 | val writer = for { 8 | v <- 42.set(Vector("The answer")) 9 | _ <- Vector("Just log something").tell 10 | w <- (v + 1).set(Vector("One more than the answer")) 11 | } yield w 12 | 13 | writer.written.map(println) 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /monad/src/main/scala/parallel/FoldMap.scala: -------------------------------------------------------------------------------- 1 | package parallel 2 | 3 | import scala.language.higherKinds 4 | import scala.collection.Iterable 5 | import scala.concurrent.{Await, ExecutionContext, Future} 6 | import scala.concurrent.duration.Duration 7 | 8 | import scalaz.{Monad, Monoid} 9 | import scalaz.Id._ 10 | import scalaz.syntax.monoid._ 11 | import scalaz.syntax.monad._ 12 | 13 | object FoldMap { 14 | def foldMap[A, B : Monoid](iter: Iterable[A])(f: A => B = (a: A) => a): B = 15 | foldMapM[A, Id, B](iter){ a => f(a).point[Id] } 16 | 17 | def foldMapM[A, M[_] : Monad, B: Monoid](iter: Iterable[A])(f: A => M[B] = (a: A) => a.point[Id]): M[B] = 18 | iter.foldLeft(mzero[B].point[M]){ (accum, elt) => 19 | for { 20 | a <- accum 21 | b <- f(elt) 22 | } yield a |+| b 23 | } 24 | 25 | implicit class IterableFoldMappable[A](iter: Iterable[A]) { 26 | def foldMap[B : Monoid](f: A => B): B = 27 | FoldMap.foldMap(iter)(f) 28 | 29 | def foldMapM[M[_] : Monad, B : Monoid](f: A => M[B] = (a: A) => a.point[Id]): M[B] = 30 | FoldMap.foldMapM(iter)(f) 31 | } 32 | } 33 | 34 | object Timing { 35 | import FoldMap._ 36 | import scala.concurrent.ExecutionContext.Implicits.global 37 | 38 | // Can we actually do work in parallel faster than in serial? Let's find out. 39 | def time[A](msg: String)(f: => A): A = { 40 | // Let Hotspot do some work 41 | f 42 | 43 | val start = System.nanoTime() 44 | val result = f 45 | val end = System.nanoTime() 46 | println(s"$msg took ${end - start} nanoseconds") 47 | result 48 | } 49 | 50 | def examples = { 51 | import scalaz.std.anyVal._ 52 | import scalaz.std.option._ 53 | import scalaz.std.list._ 54 | 55 | val seq = Seq(1, 2, 3) 56 | seq.foldMapM(a => some(a)) 57 | seq.foldMapM(a => List(a)) 58 | seq.foldMap(a => if(a % 2 == 0) some(a) else none[Int]) 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /monadTransformer/src/main/scala/FutureLogResult.scala: -------------------------------------------------------------------------------- 1 | import scalaz.{EitherT, WriterT, Monad, \/} 2 | import scalaz.concurrent.Task 3 | import scalaz.syntax.either._ 4 | import scalaz.std.vector._ 5 | 6 | object FutureLogResult { 7 | type Logged[A] = WriterT[Task, Vector[String], A] 8 | type Async[B] = EitherT[Logged, String, B] 9 | 10 | object Async { 11 | def apply[A](in: => A): Async[A] = { 12 | val value = Task.now(Vector.empty[String] -> in.right) 13 | val logged: Logged[\/[String, A]] = WriterT(value) 14 | val async: Async[A] = EitherT(logged) 15 | async 16 | } 17 | } 18 | 19 | implicit object asyncInstance extends Monad[Async] { 20 | def point[A](a: => A): Async[A] = 21 | Async(a) 22 | 23 | def bind[A, B](fa: Async[A])(f: A => Async[B]): Async[B] = 24 | fa.flatMap(f) 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /monadTransformer/src/main/scala/OptionalResult.scala: -------------------------------------------------------------------------------- 1 | import scalaz.{\/, OptionT, Monad} 2 | import scalaz.syntax.monad._ 3 | import scalaz.std.option._ 4 | 5 | object OptionalResult { 6 | type Error[A] = \/[String, A] 7 | type Result[A] = OptionT[Error, A] 8 | 9 | val result: Result[Int] = 42.point[Result] 10 | val transformed = 11 | for { 12 | value <- result 13 | } yield value.toString 14 | 15 | val failed: Result[Int] = OptionT(none[Int].point[Error]) 16 | } 17 | -------------------------------------------------------------------------------- /monoid/src/main/scala/FoldMap.scala: -------------------------------------------------------------------------------- 1 | import scalaz.Monoid 2 | import scalaz.syntax.monoid._ 3 | 4 | object FoldMap { 5 | implicit class ListFoldable[A](base: List[A]) { 6 | def foldMap[B : Monoid](f: A => B = (a: A) => a): B = 7 | base.foldLeft(mzero[B])(_ |+| f(_)) 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /monoid/src/main/scala/InstanceSelection.scala: -------------------------------------------------------------------------------- 1 | object TypeClasses { 2 | 3 | trait InvariantShow[A] { 4 | def show(in: A): String 5 | } 6 | 7 | trait CovariantShow[+A] { 8 | def show[AA >: A](in: AA): String 9 | } 10 | 11 | trait ContravariantShow[-A] { 12 | def show(in: A): String 13 | } 14 | 15 | } 16 | 17 | object Interface { 18 | import TypeClasses._ 19 | 20 | def invariant[A : InvariantShow](in: A): String = 21 | implicitly[InvariantShow[A]].show(in) 22 | 23 | def covariant[A : CovariantShow](in: A): String = 24 | implicitly[CovariantShow[A]].show(in) 25 | 26 | def contravariant[A : ContravariantShow](in: A): String = 27 | implicitly[ContravariantShow[A]].show(in) 28 | } 29 | 30 | class Animal() 31 | class Feline() extends Animal 32 | class Moggy() extends Feline 33 | 34 | object Instances { 35 | import TypeClasses._ 36 | 37 | implicit object invariantAnimal extends InvariantShow[Animal] { 38 | def show(in: Animal): String = "Animal" 39 | } 40 | 41 | implicit object covariantAnimal extends CovariantShow[Animal] { 42 | def show[AA >: Animal](in: AA): String = "Animal" 43 | } 44 | 45 | implicit object contravariantAnimal extends ContravariantShow[Animal] { 46 | def show(in: Animal): String = "Animal" 47 | } 48 | 49 | implicit object contravariantMoggy extends ContravariantShow[Moggy] { 50 | def show(in: Moggy): String = "Moggy" 51 | } 52 | } 53 | 54 | object InvariantExample { 55 | import Instances.invariantAnimal 56 | 57 | def example: String = { 58 | Interface.invariant(new Animal()) 59 | // Will not compile, because InvariantShow[Animal] is not a 60 | // subtype of InvariantShow[Feline] or InvariantShow[Moggy] 61 | // 62 | //Interface.invariant(new Feline()) 63 | //Interface.invariant(new Moggy()) 64 | } 65 | } 66 | 67 | object CovariantExample { 68 | import Instances.covariantAnimal 69 | 70 | def example: String = { 71 | Interface.covariant(new Animal()) 72 | // Will not compile, because CovariantShow[Animal] is not a 73 | // subtype of CovariantShow[Feline] or CovariantShow[Moggy] 74 | // 75 | //Interface.covariant(new Feline()) 76 | //Interface.covariant(new Moggy()) 77 | } 78 | } 79 | 80 | object ContravariantExample { 81 | import Instances.contravariantAnimal 82 | //import Instances.contravariantMoggy 83 | 84 | def example: String = { 85 | Interface.contravariant(new Animal()) 86 | // Selects contravariantAnimal but if we introduce 87 | // contravariantMoggy we can't compile due to ambiguity: both 88 | // instances are applicable 89 | // 90 | Interface.contravariant(new Moggy()) 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /monoid/src/main/scala/MonoidExamples.scala: -------------------------------------------------------------------------------- 1 | /* Examples of Monoid functionality in Scalaz */ 2 | 3 | import scalaz.Monoid 4 | 5 | object MonoidExamples { 6 | 7 | def interface = { 8 | import scalaz.std.string._ // Get String instances into scope 9 | val instance = Monoid[String] 10 | instance.append("Hi there", instance.zero) 11 | } 12 | 13 | def syntax = { 14 | import scalaz.syntax.monoid._ 15 | import scalaz.std.string._ 16 | import scalaz.std.anyVal._ 17 | 18 | "Hi " |+| "there" |+| mzero[String] 19 | 1 |+| 2 |+| mzero[Int] 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /monoid/src/main/scala/SuperAdder.scala: -------------------------------------------------------------------------------- 1 | import scalaz.Monoid 2 | import scalaz.syntax.monoid._ 3 | 4 | object SuperAdder { 5 | def add[A: Monoid](items: List[A]): A = 6 | items.foldLeft(mzero[A]){ _ |+| _ } 7 | } 8 | 9 | case class Order(unitCost: Double, quantity: Int) { 10 | val totalCost: Double = unitCost * quantity 11 | } 12 | 13 | object Order { 14 | val zero = Order(0, 0) 15 | def add(o1: Order, o2: => Order): Order = 16 | Order( 17 | (o1.totalCost + o2.totalCost) / (o1.quantity + o2.quantity), 18 | o1.quantity + o2.quantity 19 | ) 20 | 21 | implicit val orderInstance: Monoid[Order] = Monoid.instance[Order](add _, zero) 22 | } 23 | 24 | object Examples { 25 | import scalaz.std.anyVal._ 26 | import scalaz.std.option._ 27 | 28 | def ints = 29 | SuperAdder.add(List(1,2,3,4,5)) 30 | 31 | def options = 32 | SuperAdder.add(List(Some(1), None, Some(2), Some(3), Some(4), None, Some(5))) 33 | 34 | def orders = 35 | SuperAdder.add(List( 36 | Order(1, 1), 37 | Order(2, 2), 38 | Order(3, 3), 39 | Order(4, 4), 40 | Order(5, 5) 41 | )) 42 | } 43 | -------------------------------------------------------------------------------- /monoid/src/main/scala/parallel/FoldMap.scala: -------------------------------------------------------------------------------- 1 | package parallel 2 | 3 | import scala.collection.Iterable 4 | import scala.concurrent.{Await, ExecutionContext, Future} 5 | import scala.concurrent.duration.Duration 6 | 7 | import scalaz.Monoid 8 | import scalaz.syntax.monoid._ 9 | 10 | object FoldMap { 11 | def foldMapP[A, B : Monoid](iter: Iterable[A])(f: A => B = (a: A) => a)(implicit ec: ExecutionContext): B = { 12 | val nCores: Int = Runtime.getRuntime().availableProcessors() 13 | val groupSize: Int = (iter.size.toDouble / nCores.toDouble).ceil.round.toInt 14 | 15 | val groups = iter.grouped(groupSize) 16 | val futures: Iterator[Future[B]] = groups map { group => 17 | Future { group.foldLeft(mzero[B])(_ |+| f(_)) } 18 | } 19 | val result: Future[B] = Future.sequence(futures) map { iterable => 20 | iterable.foldLeft(mzero[B])(_ |+| _) 21 | } 22 | 23 | Await.result(result, Duration.Inf) 24 | } 25 | 26 | // Specialised implementation for arrays that doesn't copy 27 | def foldMapP[A, B : Monoid](arr: Array[A])(f: A => B)(implicit ec: ExecutionContext): B = { 28 | def iter(idx: Int, end: Int, result: B): B = 29 | if(idx == end) 30 | result 31 | else 32 | iter(idx + 1, end, result |+| f(arr(idx))) 33 | 34 | val nCores: Int = Runtime.getRuntime().availableProcessors() 35 | val groupSize: Int = (arr.size.toDouble / nCores.toDouble).ceil.round.toInt 36 | 37 | val futures = 38 | for(i <- 0 until nCores) yield { 39 | Future { 40 | iter(i * groupSize, i * groupSize + groupSize, mzero[B]) 41 | } 42 | } 43 | val result: Future[B] = Future.sequence(futures) map { iterable => 44 | iterable.foldLeft(mzero[B])(_ |+| _) 45 | } 46 | 47 | Await.result(result, Duration.Inf) 48 | } 49 | 50 | def foldMap[A, B : Monoid](iter: Iterable[A])(f: A => B = (a: A) => a): B = 51 | iter.foldLeft(mzero[B])(_ |+| f(_)) 52 | 53 | implicit class IterableFoldMappable[A](iter: Iterable[A]) { 54 | def foldMapP[B : Monoid](f: A => B = (a: A) => a)(implicit ec: ExecutionContext): B = 55 | FoldMap.foldMap(iter)(f) 56 | 57 | def foldMap[B : Monoid](f: A => B = (a: A) => a): B = 58 | FoldMap.foldMap(iter)(f) 59 | } 60 | 61 | implicit class ArrayFoldMappable[A](arr: Array[A]) { 62 | def foldMapP[B : Monoid](f: A => B = (a: A) => a)(implicit ec: ExecutionContext): B = 63 | FoldMap.foldMap(arr)(f) 64 | 65 | def foldMap[B : Monoid](f: A => B = (a: A) => a): B = 66 | FoldMap.foldMap(arr)(f) 67 | } 68 | } 69 | 70 | object Timing { 71 | import FoldMap._ 72 | //import scala.concurrent.ExecutionContext.Implicits.global 73 | import java.util.concurrent.Executors 74 | val threadPool = Executors.newFixedThreadPool(4) 75 | implicit val ec = ExecutionContext.fromExecutor(threadPool) 76 | 77 | // Can we actually do work in parallel faster than in serial? Let's find out. 78 | def time[A](msg: String)(f: => A): A = { 79 | // Let Hotspot do some work 80 | f 81 | 82 | val start = System.nanoTime() 83 | val result = f 84 | val end = System.nanoTime() 85 | println(s"$msg took ${end - start} nanoseconds") 86 | result 87 | } 88 | 89 | def counting(n: Int = 10000000) = { 90 | import scalaz.std.anyVal._ 91 | 92 | val data = Vector.fill(n)(1) 93 | 94 | time("Counting items in parallel") { data.foldMapP[Int]() } 95 | time("Counting items in serial ") { data.foldMap[Int]() } 96 | } 97 | 98 | def complicatedCounting(n: Int = 10000000) = { 99 | import scalaz.std.anyVal._ 100 | 101 | val data = Vector.fill(n)("1") 102 | 103 | time("Counting items in parallel") { data.foldMapP[Int](_.toInt) } 104 | time("Counting items in serial ") { data.foldMap[Int](_.toInt) } 105 | } 106 | 107 | def countingArray(n: Int = 10000000) = { 108 | import scalaz.std.anyVal._ 109 | 110 | val data = Array.fill(n)(1) 111 | 112 | time("Counting items in parallel") { data.foldMapP[Int]() } 113 | time("Counting items in serial ") { data.foldMap[Int]() } 114 | } 115 | 116 | def complicatedCountingArray(n: Int = 10000000) = { 117 | import scalaz.std.anyVal._ 118 | 119 | val data = Array.fill(n)("1") 120 | 121 | time("Counting items in parallel") { data.foldMapP[Int](_.toInt) } 122 | time("Counting items in serial ") { data.foldMap[Int](_.toInt) } 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /probability/src/main/scala/probability/Continuous.scala: -------------------------------------------------------------------------------- 1 | package probability 2 | 3 | import scala.language.higherKinds 4 | 5 | trait Continuous[F[_]] { 6 | def normal(mean: Double, variance: Double): F[Double] 7 | } 8 | -------------------------------------------------------------------------------- /probability/src/main/scala/probability/Discrete.scala: -------------------------------------------------------------------------------- 1 | package probability 2 | 3 | import scala.language.higherKinds 4 | 5 | trait Discrete[F[_]] { 6 | def discrete[A](events: List[(A,Probability)]): F[A] 7 | 8 | def pure[A](atom: A): F[A] = 9 | discrete(List(atom -> 1.0)) 10 | 11 | def uniform[A](atoms: List[A]): F[A] = { 12 | val n = atoms.length 13 | val weight = 1.0 / n 14 | discrete(atoms.map(a => a -> weight)) 15 | } 16 | 17 | def bernoulli(weight: Probability): F[Boolean] = 18 | discrete(List(true -> weight, false -> (1 - weight))) 19 | } 20 | -------------------------------------------------------------------------------- /probability/src/main/scala/probability/Enumeration.scala: -------------------------------------------------------------------------------- 1 | package probability 2 | 3 | import cats.Monad 4 | 5 | final case class Enumeration[A](events: List[(A, Double)]) { 6 | def flatMap[B](f: A => Enumeration[B]): Enumeration[B] = { 7 | Enumeration( 8 | for { 9 | (a, p1) <- this.events 10 | (b, p2) <- f(a).events 11 | } yield b -> (p2 * p1) 12 | ) 13 | } 14 | 15 | def map[B](f: A => B): Enumeration[B] = 16 | Enumeration(events.map { case (a, p) => f(a) -> p }) 17 | 18 | def normalize: Enumeration[A] = { 19 | val totalWeight = (events map { case (a, p) => p }).sum 20 | Enumeration(events map { case (a,p) => a -> (p / totalWeight) }) 21 | } 22 | 23 | def compact: Enumeration[A] = { 24 | val distinct = (events map { case (a, p) => a }).distinct 25 | def prob(a: A): Double = 26 | (events filter { case (x, p) => x == a } map { case (a, p) => p }).sum 27 | 28 | Enumeration(distinct map { a => a -> prob(a) }) 29 | } 30 | } 31 | object Enumeration { 32 | def pure[A](atom: A): Enumeration[A] = 33 | discrete(List(atom -> 1.0)) 34 | 35 | def uniform[A](atoms: List[A]): Enumeration[A] = { 36 | val n = atoms.length 37 | val weight = 1.0 / n 38 | discrete(atoms.map(a => a -> weight)) 39 | } 40 | 41 | def bernoulli(weight: Probability): Enumeration[Boolean] = 42 | discrete(List(true -> weight, false -> (1 - weight))) 43 | 44 | def discrete[A](events: List[(A, Double)]): Enumeration[A] = 45 | Enumeration(events) 46 | 47 | implicit object enumerationInstance extends Monad[Enumeration] with Discrete[Enumeration] { 48 | override def flatMap[A,B](fa: Enumeration[A])(f: A => Enumeration[B]): Enumeration[B] = 49 | fa.flatMap(f) 50 | 51 | override def map[A,B](fa: Enumeration[A])(f: A => B): Enumeration[B] = 52 | fa.map(f) 53 | 54 | override def pure[A](atom: A): Enumeration[A] = 55 | Enumeration.pure(atom) 56 | 57 | override def discrete[A](events: List[(A, Double)]): Enumeration[A] = 58 | Enumeration.discrete(events) 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /probability/src/main/scala/probability/package.scala: -------------------------------------------------------------------------------- 1 | package object probability { 2 | type Probability = Double 3 | } 4 | -------------------------------------------------------------------------------- /validation/src/main/scala/validation/Check.scala: -------------------------------------------------------------------------------- 1 | package validation 2 | 3 | object check { 4 | import cats.Semigroup 5 | import cats.data.Validated 6 | 7 | import predicate._ 8 | 9 | sealed trait Check[E,A,B] { 10 | import Check._ 11 | 12 | def map[C](f: B => C): Check[E,A,C] = 13 | Map[E,A,B,C](this, f) 14 | 15 | def flatMap[C](f: B => Check[E,A,C]) = 16 | FlatMap[E,A,B,C](this, f) 17 | 18 | def andThen[C](next: Check[E,B,C]): Check[E,A,C] = 19 | AndThen[E,A,B,C](this, next) 20 | 21 | def apply(in: A)(implicit s: Semigroup[E]): Validated[E,B] 22 | } 23 | object Check { 24 | final case class Map[E,A,B,C](check: Check[E,A,B], f: B => C) extends Check[E,A,C] { 25 | def apply(in: A)(implicit s: Semigroup[E]): Validated[E,C] = 26 | check(in) map f 27 | } 28 | final case class FlatMap[E,A,B,C](check: Check[E,A,B], f: B => Check[E,A,C]) extends Check[E,A,C] { 29 | def apply(in: A)(implicit s: Semigroup[E]): Validated[E,C] = 30 | check(in).withXor { _.flatMap (b => f(b)(in).toXor) } 31 | } 32 | final case class AndThen[E,A,B,C](check: Check[E,A,B], next: Check[E,B,C]) extends Check[E,A,C] { 33 | def apply(in: A)(implicit s: Semigroup[E]): Validated[E,C] = 34 | check(in).withXor { _.flatMap (b => next(b).toXor) } 35 | } 36 | final case class Pure[E,A,B](f: A => Validated[E,B]) extends Check[E,A,B] { 37 | def apply(in: A)(implicit s: Semigroup[E]): Validated[E,B] = 38 | f(in) 39 | } 40 | final case class PurePredicate[E,A,B](predicate: Predicate[E,A]) extends Check[E,A,A] { 41 | def apply(in: A)(implicit s: Semigroup[E]): Validated[E,A] = 42 | predicate(in) 43 | } 44 | 45 | def apply[E,A](predicate: Predicate[E,A]): Check[E,A,A] = 46 | PurePredicate(predicate) 47 | 48 | def apply[E,A,B](f: A => Validated[E,B]): Check[E,A,B] = 49 | Pure(f) 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /validation/src/main/scala/validation/CheckF.scala: -------------------------------------------------------------------------------- 1 | package validation 2 | 3 | import scalaz.{\/,-\/,\/-} 4 | import scalaz.Semigroup 5 | import scalaz.syntax.either._ // For .left and .right 6 | import scalaz.syntax.semigroup._ // For |+| 7 | 8 | final case class CheckF[E,A](f: A => E \/ A) { 9 | def and(that: CheckF[E,A])(implicit s: Semigroup[E]): CheckF[E,A] = { 10 | val self = this 11 | CheckF(a => 12 | (self(a), that(a)) match { 13 | case (-\/(e1), -\/(e2)) => (e1 |+| e2).left 14 | case (-\/(e), \/-(a)) => e.left 15 | case (\/-(a), -\/(e)) => e.left 16 | case (\/-(a1), \/-(a2)) => a.right 17 | } 18 | ) 19 | } 20 | 21 | def apply(a: A): E \/ A = 22 | f(a) 23 | } 24 | -------------------------------------------------------------------------------- /validation/src/main/scala/validation/Example.scala: -------------------------------------------------------------------------------- 1 | package validation 2 | 3 | object example { 4 | import cats.data.{Kleisli,NonEmptyList,OneAnd,Validated,Xor} 5 | import cats.std.list._ 6 | import cats.std.function._ 7 | import cats.syntax.cartesian._ 8 | import cats.syntax.validated._ 9 | import predicate._ 10 | 11 | type Error = NonEmptyList[String] 12 | def error(s: String): NonEmptyList[String] = 13 | OneAnd(s, Nil) 14 | 15 | type Result[A] = Xor[Error,A] 16 | type Check[A,B] = Kleisli[Result,A,B] 17 | // This constructor helps with type inference, which fails miserably in many cases below 18 | def Check[A,B](f: A => Result[B]): Check[A,B] = 19 | Kleisli(f) 20 | 21 | // Utilities. We could implement all the checks using regular expressions but 22 | // this shows off the compositionality of the library. 23 | def longerThan(n: Int): Predicate[Error,String] = 24 | Predicate.lift(error(s"Must be longer than $n characters")){ _.size > n } 25 | 26 | val alphanumeric: Predicate[Error,String] = 27 | Predicate.lift(error(s"Must be all alphanumeric characters")){ _.forall(_.isLetterOrDigit) } 28 | 29 | def contains(char: Char): Predicate[Error,String] = 30 | Predicate.lift(error(s"Must contain the character $char")){ _.contains(char) } 31 | 32 | def containsOnce(char: Char): Predicate[Error,String] = 33 | Predicate.lift(error(s"Must contain the character $char only once")){ 34 | _.filter(c => c == char).size == 1 35 | } 36 | 37 | // A username must contain at least four characters and consist entirely of 38 | // alphanumeric characters 39 | val checkUsername: Check[String,String] = 40 | Check((longerThan(3) and alphanumeric).run) 41 | 42 | // An email address must contain a single `@` sign. Split the string at the 43 | // `@`. The string to the left must not be empty. The string to the right must 44 | // be at least three characters long and contain a dot. 45 | val checkEmailAddress: Check[String,String] = 46 | Check { (string: String) => 47 | string split '@' match { 48 | case Array(name, domain) => (name, domain).validNel[String].toXor 49 | case other => "Must contain a single @ character".invalidNel[(String,String)].toXor 50 | } 51 | } andThen Check[(String,String),(String,String)] { 52 | (longerThan(0) zip (longerThan(3) and contains('.'))).run 53 | } map { 54 | case (name, domain) => s"${name}@${domain}" 55 | } 56 | 57 | final case class User(name: String, email: String) 58 | def makeUser(name: String, email: String): Xor[Error,User] = 59 | (checkUsername.run(name) |@| checkEmailAddress.run(email)) map (User.apply _) 60 | 61 | def go() = { 62 | println(makeUser("Noel", "noel@underscore.io")) 63 | println(makeUser("", "noel@underscore@io")) 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /validation/src/main/scala/validation/Predicate.scala: -------------------------------------------------------------------------------- 1 | package validation 2 | 3 | object predicate { 4 | import cats.Semigroup 5 | import cats.data.{Validated,Xor} 6 | import cats.syntax.semigroup._ // For |+| 7 | import cats.syntax.cartesian._ // For |@| 8 | 9 | sealed trait Predicate[E,A] { 10 | import Predicate._ 11 | 12 | def and(that: Predicate[E,A]): Predicate[E,A] = 13 | And(this, that) 14 | 15 | def or(that: Predicate[E,A]): Predicate[E,A] = 16 | Or(this, that) 17 | 18 | def zip[B](that: Predicate[E,B]): Predicate[E,(A,B)] = 19 | Zip(this, that) 20 | 21 | def run(implicit s: Semigroup[E]): A => Xor[E,A] = 22 | (a: A) => this.apply(a).toXor 23 | 24 | def apply(a: A)(implicit s: Semigroup[E]): Validated[E,A] 25 | } 26 | object Predicate { 27 | final case class And[E,A](left: Predicate[E,A], right: Predicate[E,A]) extends Predicate[E,A] { 28 | def apply(a: A)(implicit s: Semigroup[E]): Validated[E,A] = 29 | (left(a) |@| right(a)) map { (_, _) => a } 30 | } 31 | final case class Or[E,A](left: Predicate[E,A], right: Predicate[E,A]) extends Predicate[E,A] { 32 | def apply(a: A)(implicit s: Semigroup[E]): Validated[E,A] = 33 | { 34 | import Validated._ // For Valid and Invalid 35 | left(a) match { 36 | case Valid(a1) => Valid(a) 37 | case Invalid(e1) => 38 | right(a) match { 39 | case Valid(a2) => Valid(a) 40 | case Invalid(e2) => Invalid(e1 |+| e2) 41 | } 42 | } 43 | } 44 | } 45 | final case class Zip[E,A,B](left: Predicate[E,A], right: Predicate[E,B]) extends Predicate[E,(A,B)] { 46 | def apply(a: (A,B))(implicit s: Semigroup[E]): Validated[E,(A,B)] = { 47 | val (theA, theB) = a 48 | (left(theA) |@| right(theB)).tupled 49 | } 50 | } 51 | final case class Pure[E,A,B](f: A => Validated[E,B]) extends Predicate[E,A] { 52 | def apply(a: A)(implicit s: Semigroup[E]): Validated[E,A] = 53 | f(a) map (_ => a) 54 | } 55 | 56 | def apply[E,A,B](f: A => Validated[E,B]): Predicate[E,A] = 57 | Pure(f) 58 | 59 | def lift[E,A](msg: E)(pred: A => Boolean): Predicate[E,A] = 60 | Pure { (a: A) => 61 | if(pred(a)) 62 | Validated.valid(a) 63 | else 64 | Validated.invalid(msg) 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /validation/src/test/scala/validation/CheckSpec.scala: -------------------------------------------------------------------------------- 1 | package validation 2 | 3 | import org.scalatest.{Inside,Matchers,WordSpec} 4 | import org.scalatest.prop.GeneratorDrivenPropertyChecks 5 | 6 | class CheckSpec extends WordSpec with Matchers with GeneratorDrivenPropertyChecks with Inside { 7 | import cats.data.{NonEmptyList,OneAnd,Validated} 8 | import cats.std.list._ 9 | import check._ 10 | import predicate._ 11 | 12 | type Pred[A] = Predicate[NonEmptyList[String], A] 13 | 14 | type Error = NonEmptyList[String] 15 | def error(s: String): NonEmptyList[String] = 16 | OneAnd(s, Nil) 17 | 18 | val even: Pred[Int] = 19 | Predicate.lift(error("Must be even")){ i => Math.abs(i % 2) == 0 } 20 | 21 | val odd: Pred[Int] = 22 | Predicate.lift(error("Must be odd")){ i => Math.abs(i % 2) == 1 } 23 | 24 | val noMoreThanMax: Pred[Int] = 25 | Predicate.lift(error("Must be less than MaxValue")){ _ <= Int.MaxValue } 26 | 27 | val noLessThanMin: Pred[Int] = 28 | Predicate.lift(error("Must be greater than MinValue")){ _ >= Int.MinValue } 29 | 30 | "A Check" when { 31 | "applied to a value" must { 32 | "fail if its component predicate fails" in { 33 | forAll { (n: Int) => 34 | Check(even and odd)(n).isInvalid should === (true) 35 | } 36 | } 37 | "succeed if component predicate succeeds" in { 38 | forAll { (n: Int) => 39 | Check(noMoreThanMax and noLessThanMin)(n).isValid should === (true) 40 | } 41 | } 42 | 43 | "apply any map" in { 44 | forAll { (n: Int) => 45 | val result = (Check(even or odd) map (n => n + 42))(n) 46 | inside(result) { case Validated.Valid(i) => 47 | i should === (n + 42) 48 | } 49 | } 50 | } 51 | 52 | "apply any flatMap" in { 53 | forAll { (n: Int) => 54 | val check = 55 | Check(even or odd) flatMap { i => 56 | if(i < 0) 57 | Check(noMoreThanMax) map { i => "negative" } 58 | else 59 | Check(noLessThanMin) map { i => "not negative" } 60 | } 61 | 62 | inside(check(n)) { case Validated.Valid(s) => 63 | s should (equal ("negative") or equal ("not negative")) 64 | } 65 | } 66 | } 67 | } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /validation/src/test/scala/validation/PredicateSpec.scala: -------------------------------------------------------------------------------- 1 | package validation 2 | 3 | import org.scalatest.{Matchers,WordSpec} 4 | import org.scalatest.prop.GeneratorDrivenPropertyChecks 5 | 6 | class PredicateSpec extends WordSpec with Matchers with GeneratorDrivenPropertyChecks { 7 | import cats.data.{NonEmptyList,OneAnd,Validated} 8 | import cats.std.list._ 9 | import predicate._ 10 | 11 | type Pred[A] = Predicate[NonEmptyList[String], A] 12 | 13 | def error(s: String): NonEmptyList[String] = 14 | OneAnd(s, Nil) 15 | 16 | val even: Pred[Int] = 17 | Predicate.lift(error("Must be even")){ i => Math.abs(i % 2) == 0 } 18 | 19 | val odd: Pred[Int] = 20 | Predicate.lift(error("Must be odd")){ i => Math.abs(i % 2) == 1 } 21 | 22 | val noMoreThanMax: Pred[Int] = 23 | Predicate.lift(error("Must be less than MaxValue")){ _ <= Int.MaxValue } 24 | 25 | val noLessThanMin: Pred[Int] = 26 | Predicate.lift(error("Must be greater than MinValue")){ _ >= Int.MinValue } 27 | 28 | val greaterThanMax: Pred[Int] = 29 | Predicate.lift(error("Must be greater than MaxValue")){ _ > Int.MaxValue } 30 | 31 | val lessThanMin: Pred[Int] = 32 | Predicate.lift(error("Must be less than MinValue")){ _ < Int.MinValue } 33 | 34 | "A Predicate" when { 35 | "combined with and" must { 36 | "fail if either component predicate fails" in { 37 | forAll { (n: Int) => 38 | (even and odd)(n).isInvalid should === (true) 39 | } 40 | } 41 | "succeed if both component predicates succeed" in { 42 | forAll { (n: Int) => 43 | (noMoreThanMax and noLessThanMin)(n).isValid should === (true) 44 | } 45 | } 46 | } 47 | 48 | "combined with or" must { 49 | "fail if both component predicates fail" in { 50 | forAll { (n: Int) => 51 | (greaterThanMax or lessThanMin)(n).isInvalid should === (true) 52 | } 53 | } 54 | "succeed if either component predicate succeeds" in { 55 | forAll { (n: Int) => 56 | (even or odd)(n).isValid should === (true) 57 | } 58 | } 59 | } 60 | 61 | "combined with zip" must { 62 | "fail if either component predicate fails" in { 63 | forAll { (m: Int, n: Int) => 64 | (greaterThanMax zip noMoreThanMax)( (m,n) ).isInvalid should === (true) 65 | } 66 | } 67 | "succeed if both component predicates succeed" in { 68 | forAll { (m: Int, n: Int) => 69 | (noMoreThanMax zip noLessThanMin)( (m,n) ).isValid should === (true) 70 | } 71 | } 72 | } 73 | } 74 | } 75 | --------------------------------------------------------------------------------