Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- package me.ngrid.cats
- import cats._
- import cats.data.Validated.{Invalid, Valid}
- import cats.data._
- import cats.instances.all._
- import cats.syntax.all._
- import scala.concurrent.ExecutionContext.Implicits.global
- import scala.concurrent.duration._
- import scala.concurrent.{Await, Future}
- //import scala.language.postfixOps
- object CatsPractice {
- def foldRight[A, B](as: List[A], acc: B)(fn: (A, B) => B): B =
- foldRight(as, Eval.now(acc))(fn).value
- def foldRight[A, B](as: List[A], acc: Eval[B])(fn: (A, B) => B): Eval[B] = {
- as match {
- case head :: tail =>
- val a = acc.map(x => fn(head, x))
- Eval.defer(foldRight(tail, a)(fn))
- case Nil =>
- acc
- }
- }
- def main(args: Array[String]): Unit = {
- println(foldRight((0 to 50000).toList, 0) { (l, a) =>
- a + l
- })
- }
- }
- object LoginHacking {
- case class Db(usernames: Map[Int, String], passwords: Map[String, String])
- type DbReader[A] = Reader[Db, A]
- def findUsername(userId: Int): DbReader[Option[String]] = Reader((db: Db) =>
- db.usernames.get(userId)
- )
- def checkPassword(username: String, password: String): DbReader[Boolean] =
- Reader((db: Db) => db.passwords.get(username).contains(password))
- def checkLogin(userId: Int, password: String): DbReader[Boolean] =
- for {
- uname <- findUsername(userId)
- check <- uname.fold(false.pure[DbReader])(checkPassword(_, password))
- } yield check
- }
- object PostfixCalculator {
- type CalcState[A] = State[List[Int], A]
- def evalOne(s: Char): CalcState[Int] = s match {
- case '*' => operator(_ * _)
- case '+' => operator(_ + _)
- case '-' => operator(_ - _)
- case '/' => operator(_ / _)
- case num => constant(num.toString.toInt)
- }
- def operator(f: (Int, Int) => Int): CalcState[Int] = State {
- case one :: two :: tail =>
- val x = f(one, two)
- (x :: tail, x)
- case x => (x, -1)
- }
- def constant(v: Int): CalcState[Int] = State { x =>
- (v :: x, v)
- }
- def evalAll(l: Seq[Char]): CalcState[Int] = {
- l.map(evalOne).foldLeft(0.pure[CalcState]) {
- _ followedBy _
- }
- }
- def main(args: Array[String]): Unit = {
- println(evalAll("12+3*6+").runA(Nil).value)
- println(evalAll("").runA(Nil).value)
- }
- }
- object BranchingMonad {
- sealed trait Tree[+A]
- final case class Branch[A](left: Tree[A], right: Tree[A]) extends Tree[A]
- final case class Leaf[A](value: A) extends Tree[A]
- final case class Empty[A]() extends Tree[A]
- def branch[A](left: Tree[A], right: Tree[A]): Tree[A] =
- Branch(left, right)
- def leaf[A](value: A): Tree[A] =
- Leaf(value)
- def empty[A]: Tree[A] = Empty()
- implicit val monadLike: Monad[Tree] = new Monad[Tree] {
- override def flatMap[A, B](fa: Tree[A])(f: (A) => Tree[B]): Tree[B] = fa match {
- case Branch(left, right) => Branch(flatMap(left)(f), flatMap(right)(f))
- case Leaf(value) => f(value)
- case _: Empty[_] => Empty()
- }
- override def tailRecM[A, B](a: A)(f: (A) => Tree[Either[A, B]]): Tree[B] = {
- f(a) match {
- case Branch(left, right) =>
- Branch(
- flatMap(left) {
- case Left(v) => tailRecM(v)(f)
- case Right(v) => pure(v)
- },
- flatMap(right) {
- case Left(v) => tailRecM(v)(f)
- case Right(v) => pure(v)
- }
- )
- case Leaf(Left(l)) => tailRecM(l)(f)
- case Leaf(Right(r)) => pure(r)
- case _: Empty[_] => Empty()
- }
- }
- override def pure[A](x: A): Tree[A] = Leaf(x)
- }
- def main(args: Array[String]): Unit = {
- println {
- for {
- a <- branch(leaf(100), empty)
- b <- branch(leaf(a - 10), leaf(a + 10))
- c <- branch(leaf(b - 1), leaf(b + 1))
- } yield b
- }
- }
- }
- object MonadsTransformAndRoll {
- //type Response[A] = Future[Either[String, A]]
- type Response[A] = EitherT[Future, String, A]
- val powerLevels = Map(
- "Jazz" -> 6,
- "Bumblebee" -> 8,
- "Hot Rod" -> 10
- )
- def getPowerLevel(autobot: String): Response[Int] = {
- powerLevels.get(autobot) match {
- case Some(v) => v.pure[Response]
- case None => EitherT.left(Future(s"$autobot is unreacheable at this moment"))
- }
- }
- def canSpecialMove(ally1: String, ally2: String): Response[Boolean] = {
- for {
- a <- getPowerLevel(ally1)
- b <- getPowerLevel(ally2)
- } yield a + b > 15
- }
- def tacticalReport(ally1: String, ally2: String): String = {
- val f = canSpecialMove(ally1, ally2).map {
- case true => s"$ally1 and $ally2 are ready to rollout"
- case false => s"$ally1 and $ally2 are still charging"
- }
- Await.result(f.value, 1.seconds) match {
- case Left(s) => "Comms Error: " + s
- case Right(s) => s
- }
- }
- def main(args: Array[String]): Unit = {
- println(tacticalReport("Jazz", "Hot Rod"))
- println(tacticalReport("Bumblebee", "Jazz"))
- println(tacticalReport("Bumblebee", "Optimus"))
- }
- }
- object WooohCartesians {
- case class Cat(name: String, born: Int, color: String)
- def main(args: Array[String]): Unit = {
- val garf = (Option("Garfield") |@| Option(21) |@| Option("Orange")).map(Cat.apply)
- // val garf = (Option("Garfield") |@| None |@| Option("Orange")).map(Cat.apply)
- println(garf)
- }
- }
- object CartisianComposition {
- case class Cat(name: String, dob: Int, favoriteFood: List[String])
- implicit val catMonoid = (
- Monoid[String] |@| Monoid[Int] |@| Monoid[List[String]]
- )
- //Why do we need an imap here instead of just map?
- // .map(Cat.apply)
- .imap(Cat.apply)(x => (x.name, x.dob, x.favoriteFood))
- def main(args: Array[String]): Unit = {
- val garfield = Cat("Garfield", 1978, List("Lasagne"))
- val heathcliff = Cat("Heathcliff", 1988, List("Junk Food"))
- println(garfield |+| heathcliff)
- }
- }
- object FormValidation {
- case class User(name: String, age: Int)
- type ErrorOr[A] = Either[Vector[String], A]
- type AllErrorsOr[A] = Validated[Vector[String], A]
- def main(args: Array[String]): Unit = {
- println(readUser {
- Map(
- "name" -> "nick",
- "age" -> "27"
- )
- })
- println(readUser {
- Map(
- "name" -> "",
- "age" -> "-7"
- )
- })
- }
- def readUser(m: Map[String, String]): AllErrorsOr[User] = {
- val v = readName(m).toValidated |@| readAge(m).toValidated
- v.map(User.apply)
- }
- def readName(m: Map[String, String]): ErrorOr[String] = {
- val v = for {
- str <- m.readValue("name")
- _ <- nonBlank(str)
- } yield str
- v.leftMap(_.map(x => "name: " + x))
- }
- def readAge(m: Map[String, String]): ErrorOr[Int] = {
- val v = for {
- str <- m.readValue("age")
- i <- parseInt(str)
- _ <- nonNegative(i)
- } yield i
- v.leftMap(_.map(x => "age: " + x))
- }
- def nonBlank(s: String): ErrorOr[String] = {
- if (s.isEmpty) Vector(s"field was empty").asLeft
- else s.asRight
- }
- def parseInt(s: String): ErrorOr[Int] = {
- Either.catchOnly[NumberFormatException](s.toInt).
- leftMap(_ => Vector(s"$s is not a number"))
- }
- def nonNegative(i: Int): ErrorOr[Int] = {
- if (i < 0) Vector(s"$i is negative").asLeft
- else i.asRight
- }
- implicit class MapWithErrors[K, V](m: Map[K, V]) {
- def readValue(k: K): ErrorOr[V] = {
- m.get(k) match {
- case Some(v) => v.asRight
- case None => Vector(s"property $k was not found").asLeft
- }
- }
- }
- }
- object Folding {
- def main(args: Array[String]): Unit = {
- val l = List(1, 2, 3)
- println(l.foldLeft(List.empty[Int])((x, y) => y :: x))
- println(l.foldRight(List.empty[Int])((x, y) => x :: y))
- }
- case class HyperList[T](l: T*) {
- def map[U](f: T => U): HyperList[U] = {
- val n = l.foldRight(List.empty[U])((i, a) => f(i) :: a)
- HyperList(n: _*)
- }
- def flatMap[U](f: T => HyperList[U]): HyperList[U] = {
- val out = l.foldRight(List.empty[U]) { (i, a) =>
- f(i).l ++: a
- }
- HyperList(out: _*)
- }
- def filter(f: T => Boolean): HyperList[T] = {
- val out = l.foldRight(List.empty[T]) { (i, a) =>
- if (f(i)) i :: a else a
- }
- HyperList(out: _*)
- }
- def sum(implicit m: Monoid[T]): T = {
- l.foldRight(m.empty)(m.combine)
- }
- }
- }
- object AsyncTesting {
- trait UptimeClient[F[_]] {
- def getUptime(hostname: String): F[Int]
- }
- class TestUptimeClient(hosts: Map[String, Int]) extends UptimeClient[Id] {
- override def getUptime(hostname: String): Int = {
- hosts.getOrElse(hostname, 0)
- }
- }
- class UptimeService[F[_] : Applicative](client: UptimeClient[F]) {
- def getTotalUptime(hostnames: List[String]): F[Int] = {
- hostnames.traverse(client.getUptime).map(_.sum)
- }
- }
- def main(args: Array[String]): Unit = {
- val hosts = Map("host1" -> 10, "host2" -> 6)
- val client = new TestUptimeClient(hosts)
- val svc = new UptimeService(client)
- val actual = svc.getTotalUptime(hosts.keys.toList)
- val expected = hosts.values.toList.sum
- assert(actual == expected)
- }
- }
- object PygmyHadoop {
- val concurrency = Runtime.getRuntime.availableProcessors()
- def foldMap[A, B: Monoid](v: Vector[A])(f: A => B): B = {
- v.foldLeft(Monoid[B].empty)((a, i) => a |+| f(i))
- }
- def parallelFoldMap[A, B: Monoid](v: Vector[A])(f: A => B): Future[B] = {
- val n = (1.0 * v.length / concurrency).ceil.toInt
- // val m: Future[Vector[B]] = v.grouped(n).map { x =>
- // Future {
- // Foldable[Vector].foldLeft(x, Monoid[B].empty)((a, i) => a |+| f(i))
- // }
- // }.toVector.sequence
- // m map { x =>
- // x.foldLeft(Monoid[B].empty)((a, i) => a |+| i)
- // }
- //THe IDE suck at detecting the type of the container in traverse so we hint, still valid code that compiles without it tho.
- v.grouped(n).toVector.traverse[Future, B] { x =>
- Future(
- x.foldMap(f)
- )
- }.map(_.combineAll)
- }
- def main(args: Array[String]): Unit = {
- println {
- foldMap(Vector(1, 2, 3))(x => x.toString + "! ")
- }
- println {
- Await.result(parallelFoldMap((1 to 10000).toVector)(x => x * 2), 3.seconds)
- }
- println {
- foldMap("Hello world!".toVector)(_.toString.toUpperCase)
- }
- println {
- Await.result(parallelFoldMap("Hello world!".toVector)(_.toString.toUpperCase), 3.seconds)
- }
- }
- }
- object DataValidationStudy {
- final case class User(username: String, email: String)
- object User {
- def create(username: String, email: String): Validated[Errors, User] = {
- (checkUsername(username).toValidated |@| checkEmail(email).toValidated).map(User.apply)
- }
- }
- def main(args: Array[String]): Unit = {
- println(User.create("Noel1", "noel@underscore.io"))
- println(User.create("", "dave@underscore@io"))
- }
- def checkUsername: Check[String, String] = {
- import StringValidators._
- check((longerThan(4) and alphanumeric).run)
- }
- def checkEmail: Check[String, String] = {
- import StringValidators._
- def split: Check[String, (String, String)] = {
- check(_.split('@') match {
- case Array(first, second) =>
- Right((first, second))
- case other =>
- Left(error("Must contain single @ character"))
- })
- }
- def join: Check[(String, String), String] = {
- check { case (l, r) => (checkLeft(l) |@| checkRight(r)).map(_ + "@" + _) }
- }
- def checkLeft: Check[String, String] = checkPred(longerThan(0))
- def checkRight: Check[String, String] = checkPred(longerThan(3) and contains('.'))
- split andThen join
- }
- def error(s: String) = NonEmptyList(s, Nil)
- object StringValidators {
- def longerThan(n: Int): Predicate[Errors, String] = {
- Predicate.lift(error(s"String must be longer than $n"), _.length > n)
- }
- def alphanumeric: Predicate[Errors, String] = {
- Predicate.lift(error("String must be alpha numeric"), str => str.forall(_.isLetterOrDigit))
- }
- def contains(c: Char): Predicate[Errors, String] = {
- Predicate.lift(error(s"String must contain char $c"), _.contains(c))
- }
- def containsOnce(c: Char): Predicate[Errors, String] = {
- Predicate.lift(error(s"String must contain char $c only once"), i => i.filter(_ == c).length == 1)
- }
- }
- sealed trait Predicate[E, A] {
- import Predicate._
- def apply(value: A)(implicit s: Semigroup[E]): Validated[E, A] = {
- this match {
- case Pure(f) => f(value)
- case And(left, right) =>
- val m = left(value) |@| right(value)
- m.map((_, _) => value)
- case Or(left, right) =>
- left(value) match {
- case Valid(v) => Valid(v)
- case Invalid(e) =>
- right(value) match {
- case Valid(v) => Valid(v)
- case Invalid(e2) => Invalid(e |+| e2)
- }
- }
- }
- }
- def run(implicit s: Semigroup[E]): A => Either[E, A] = {
- a => this.apply(a).toEither
- }
- def and(that: Predicate[E, A]): Predicate[E, A] = {
- And(this, that)
- }
- def or(that: Predicate[E, A]): Predicate[E, A] = {
- Or(this, that)
- }
- }
- object Predicate {
- def apply[E, A](f: A => Validated[E, A]): Predicate[E, A] = Pure(f)
- def lift[E, A](e: E, f: A => Boolean): Predicate[E, A] = {
- Pure { a => if (f(a)) a.valid else e.invalid }
- }
- final case class And[E, A](left: Predicate[E, A], right: Predicate[E, A]) extends Predicate[E, A]
- final case class Or[E, A](left: Predicate[E, A], right: Predicate[E, A]) extends Predicate[E, A]
- final case class Pure[E, A](func: A => Validated[E, A]) extends Predicate[E, A]
- }
- type Errors = NonEmptyList[String]
- type Result[A] = Either[Errors, A]
- type Check[A, B] = Kleisli[Result, A, B]
- def check[A, B](func: A => Result[B]): Check[A, B] = {
- Kleisli(func)
- }
- def checkPred[A](pred: Predicate[Errors, A]): Check[A, A] =
- Kleisli[Result, A, A](pred.run)
- // sealed trait Check[E, A, B] {
- // def apply(a: A): Validated[E, B]
- //
- // def map[C](func: B => C): Check[E, A, C] = {
- // Check.Map(this, func)
- // }
- //
- // def flatMap[C](func: B => Check[E, A, C]): Check[E, A, C] = {
- // Check.FlatMap(this, func)
- // }
- //
- // def andThen[C](c: Check[E, B, C]): Check[E, A, C] = {
- // Check.AndThen(this, c)
- // }
- // }
- // object Check {
- //
- // final case class Map[E, A, B, C](c: Check[E, A, B], f: B => C) extends Check[E, A, C] {
- // override def apply(a: A): Validated[E, C] = {
- // c(a).map(f)
- // }
- // }
- //
- // final case class AndThen[E, A, B, C](c1: Check[E, A, B], c2: Check[E, B, C]) extends Check[E, A, C] {
- // override def apply(a: A): Validated[E, C] = {
- // c1(a) match {
- // case Valid(v) => c2(v)
- // case e: Invalid[E] => e
- // }
- // }
- // }
- //
- // final case class FlatMap[E, A, B, C](c: Check[E, A, B], f: B => Check[E, A, C]) extends Check[E, A, C] {
- // override def apply(a: A): Validated[E, C] = {
- // c(a) match {
- // case Valid(v) => f(v)(a)
- // case e: Invalid[E] => e
- // }
- // }
- // }
- //
- // final case class Pure[E, A, B](f: A => Validated[E, B]) extends Check[E, A, B] {
- // override def apply(a: A): Validated[E, B] = f(a)
- // }
- //
- // final case class PurePredicate[E: Semigroup, A](p: Predicate[E, A]) extends Check[E, A, A] {
- // override def apply(a: A): Validated[E, A] = p(a)
- // }
- //
- // def apply[E: Semigroup, A](p: Predicate[E, A]): Check[E, A, A] = {
- // PurePredicate(p)
- // }
- //
- // def apply[E: Semigroup, A, B](f: A => Validated[E, B]): Check[E, A, B] = {
- // Pure(f)
- // }
- // }
- }
- // Commutative Replicated Datatypes
- object CrdtStudy {
- // final case class GCounter[A](counters: Map[String, A]) {
- // def increment(machine: String, amount: A)(implicit m: Monoid[A]): GCounter[A] = {
- // val c = counters.getOrElse(machine, m.empty) |+| amount
- // copy(counters + (machine -> c))
- // }
- //
- // def get: A = {
- // counters.foldMap(identity)
- // }
- //
- // def merge(that: GCounter[A])(implicit b: BoundedSemiLattice[A]): GCounter[A] = {
- // GCounter(this.counters |+| that.counters)
- // }
- //
- // }
- trait GCounter[F[_, _], K, V] {
- def increment(f: F[K, V])(machine: K, amount: V)(implicit m: Monoid[V]): F[K, V]
- def total(f: F[K, V])(implicit m: Monoid[V]): V
- def merge(f: F[K, V], that: F[K, V])(implicit m: BoundedSemiLattice[V]): F[K, V]
- }
- object GCounter {
- def apply[F[_, _], K, V](implicit g: GCounter[F, K, V]): GCounter[F, K, V] = g
- implicit class GCounterOps[F[_, _], K, V](f: F[K, V]) {
- def increment(key: K, value: V)(implicit g: GCounter[F, K, V], m: Monoid[V]): F[K, V] =
- g.increment(f)(key, value)
- def total(implicit g: GCounter[F, K, V], m: Monoid[V]): V =
- g.total(f)
- def merge(that: F[K, V])(implicit g: GCounter[F, K, V], b: BoundedSemiLattice[V]): F[K, V] =
- g.merge(f, that)
- }
- implicit def keyValueInstance[F[_, _], K, V](implicit k: KeyValueStore[F], km: Monoid[F[K, V]], kf: Foldable[({type l[A] = F[K, A]})#l]): GCounter[F, K, V] =
- new GCounter[F, K, V] {
- import KeyValueStore._ // For KeyValueStore syntax
- def increment(f: F[K, V])(key: K, value: V)(implicit m: Monoid[V]): F[K, V] =
- f + (key, (f.getOrElse(key, m.empty) |+| value))
- def total(f: F[K, V])(implicit m: Monoid[V]): V =
- f.foldMap(identity _)
- def merge(f1: F[K, V], f2: F[K, V])(implicit b: BoundedSemiLattice[V]): F[K, V] =
- f1 |+| f2
- }
- }
- trait KeyValueStore[F[_, _]] {
- def +[K, V](f: F[K, V])(key: K, value: V): F[K, V]
- def get[K, V](f: F[K, V])(key: K): Option[V]
- def getOrElse[K, V](f: F[K, V])(key: K, or: V): V =
- get(f)(key).getOrElse(or)
- }
- object KeyValueStore {
- implicit class KeyValueStoreOps[F[_, _], K, V](f: F[K, V]) {
- def +(key: K, value: V)(implicit s: KeyValueStore[F]): F[K, V] = s.+(f)(key, value)
- def get(key: K)(implicit s: KeyValueStore[F]): Option[V] = s.get(f)(key)
- def getOrElse(key: K, or: V)(implicit s: KeyValueStore[F]): V = s.getOrElse(f)(key, or)
- }
- implicit object mapKVStore extends KeyValueStore[Map] {
- override def +[K, V](f: Map[K, V])(key: K, value: V): Map[K, V] = f + (key -> value)
- override def get[K, V](f: Map[K, V])(key: K): Option[V] = f.get(key)
- }
- }
- trait BoundedSemiLattice[A] extends Monoid[A] {
- def combine(a1: A, a2: A): A
- def empty: A
- }
- implicit val intLattice: BoundedSemiLattice[Int] = new BoundedSemiLattice[Int] {
- override def combine(a1: Int, a2: Int): Int = a1 max a2
- override def empty: Int = 0
- }
- implicit def latticeForSets[A]: BoundedSemiLattice[Set[A]] = new BoundedSemiLattice[Set[A]] {
- override def combine(a1: Set[A], a2: Set[A]): Set[A] = a1 union a2
- override def empty: Set[A] = Set.empty[A]
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement