Created
February 25, 2016 20:04
-
-
Save julien-truffaut/b462de25aaf54e4bae81 to your computer and use it in GitHub Desktop.
Free example scala coding dojo
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package freee | |
import scalaz.\/ | |
import scalaz.concurrent.Task | |
object Example extends App { | |
import Interact._ | |
val program: API[Unit] = for { | |
_ <- tell("Hey") | |
name <- ask("What's your name") | |
_ <- tell(s"Your name is $name") | |
} yield () | |
val interactToTask: NaturalTransformation[Interact, Task] = new NaturalTransformation[Interact, Task] { | |
import scala.io.StdIn | |
def apply[A](fa: Interact[A]): Task[A] = fa match { | |
case Ask(prompt, f) => Task.delay(f(StdIn.readLine(prompt))) | |
case Tell(msg, a) => Task.delay{ | |
println(msg) | |
a | |
} | |
} | |
} | |
val taskProgram = program.transform(interactToTask): Free[Task, Unit] | |
def runTask(f: Free[Task, Unit]): Unit = f match { | |
case Return(a) => a | |
case Bind(fi, k) => fi.map(i => runTask(k(i))).run | |
} | |
runTask(taskProgram) | |
type Alegrabe[A] = Interact[A] \/ Http[A] | |
type APIV2[A] = Free[Alegrabe, A] | |
} | |
sealed trait Http[A] | |
// case class get ... |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package freee | |
sealed trait Free[F[_], A] { // F ~ List Option Future | |
def flatMap[B](f: A => Free[F, B])(implicit ev: Functor[F]): Free[F, B] = this match { | |
case Return(a) => f(a) | |
case Bind(fi, k) => Bind(fi, (i: Any) => k(i).flatMap(f)) | |
} | |
def map[B](f: A => B)(implicit ev: Functor[F]): Free[F, B] = flatMap(a => Return(f(a))) | |
def transform[G[_]](nat: NaturalTransformation[F, G]): Free[G, A] = this match { | |
case Return(a) => Return(a) | |
case Bind(fi, k) => Bind(nat.apply(fi), (i: Any) => k(i).transform(nat)) | |
} | |
} | |
case class Return[F[_], A](a: A) extends Free[F, A] | |
case class Bind[F[_], I, A](fi: F[I], k: I => Free[F, A]) extends Free[F, A] | |
trait Functor[F[_]]{ | |
def map[A, B](fa: F[A])(f: A => B): F[B] | |
} | |
trait Monad[F[_]] extends Functor[F] { | |
def flatMap[A, B](fa: F[A])(f: A => F[B]): F[B] | |
def pure[A](a: A): F[A] | |
def map[A, B](fa: F[A])(f: A => B): F[B] = flatMap(fa)(a => pure(f(a))) | |
def flatten[A](ffa: F[F[A]]): F[A] = flatMap(ffa)(identity) | |
} | |
// F[_] and Functor[F] => Monad[Free[F, A]] | |
object Free { | |
def lift[F[_],A](fa: F[A]): Free[F,A] = | |
Bind(fa, (a: A) => Return(a)) | |
implicit def monadForFree[F[_]](implicit ev: Functor[F]): Monad[({type λ[α] = Free[F, α]})#λ] = // Free[F, ?] | |
new Monad[({type λ[α] = Free[F, α]})#λ] { | |
def flatMap[A, B](fa: Free[F, A])(f: A => Free[F, B]): Free[F, B] = | |
fa.flatMap(f) | |
def pure[A](a: A): Free[F, A] = Return(a) | |
} | |
// Reasonably priced http://functionaltalks.org/2014/11/23/runar-oli-bjarnason-free-monad/ | |
// Freer http://okmij.org/ftp/Haskell/extensible/more.pdf | |
// modern FP http://degoes.net/articles/modern-fp/ | |
// cats Free | |
// https://github.com/typelevel/cats/blob/master/core/src/main/scala/cats/free/Free.scala | |
// http://typelevel.org/cats/tut/freemonad.html | |
// haskell Free https://hackage.haskell.org/package/free-4.12.4/docs/Control-Monad-Free.html | |
} | |
sealed trait Interact[A] | |
case class Ask[A](prompt: String, f: String => A) extends Interact[A] | |
case class Tell[A](msg: String, a: A) extends Interact[A] | |
object Interact { | |
implicit def functor: Functor[Interact] = new Functor[Interact] { | |
def map[A, B](fa: Interact[A])(f: A => B): Interact[B] = fa match { | |
case Ask(p, g) => Ask(p, f compose g) | |
case Tell(m, a) => Tell(m, f(a)) | |
} | |
} | |
type API[A] = Free[Interact, A] | |
def tell(msg: String): API[Unit] = | |
Free.lift(Tell(msg, ())) | |
def ask(prompt: String): API[String] = | |
Free.lift(Ask(prompt, identity)) | |
} | |
trait NaturalTransformation[F[_], G[_]]{ | |
def apply[A](fa: F[A]): G[A] | |
} | |
object NaturalTransformation { | |
val listToOption = new NaturalTransformation[List, Option] { | |
override def apply[A](fa: List[A]): Option[A] = fa.headOption | |
} | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment