SlideShare una empresa de Scribd logo
1 de 72
Descargar para leer sin conexión
POST-FREE:
LIFE AFTER
FREE MONADSJOHN A. DE GOES — @JDEGOES
OUTLINE
> Free What?
> Live Free...
> ...Or Die Hard
> Exploration of Solutions
> Hacks for Free
> Reconstructing Free
> Fixing Free
> Closing Thoughts
FREE WHAT?
REINVENTING FREE: PURE EFFECTS
data ConsoleIO
= WriteLine String ConsoleIO
| ReadLine (String -> ConsoleIO)
| End
sealed trait ConsoleIO
final case class WriteLine(line: String, then: ConsoleIO) extends ConsoleIO
final case class ReadLine(process: String => ConsoleIO) extends ConsoleIO
final case object End extends ConsoleIO
FREE WHAT?
REINVENTING FREE: PURE EFFECTS W/RETURNS
data ConsoleIO a
= WriteLine String (ConsoleIO a)
| ReadLine (String -> ConsoleIO a)
| EndWith a
sealed trait ConsoleIO[A]
final case class WriteLine[A](line: String, then: ConsoleIO[A])
extends ConsoleIO[A]
final case class ReadLine[A](process: String => ConsoleIO[A])
extends ConsoleIO[A]
final case class EndWith[A](value: A) extends ConsoleIO[A]
FREE WHAT?
REINVENTING FREE: PURE EFFECTS W/MAP (PURESCRIPT)
data ConsoleIO a
= WriteLine String (ConsoleIO a)
| ReadLine (String -> ConsoleIO a)
| EndWith a
| Map (forall z. (forall a0. ConsoleIO a0 -> (a0 -> a) -> z) -> z)
FREE WHAT?
REINVENTING FREE: PURE EFFECTS W/MAP (SCALA)
sealed trait ConsoleIO[A] {
def map[B](f: A => B): Console[B] = Map(this, f)
}
final case class WriteLine[A](line: String, then: ConsoleIO[A])
extends ConsoleIO[A]
final case class ReadLine[A](process: String => ConsoleIO[A])
extends ConsoleIO[A]
final case class EndWith[A](value: A) extends ConsoleIO[A]
final case class Map[A0, A](v: ConsoleIO[A0], f: A0 => A)
extends ConsoleIO[A]
FREE WHAT?
REINVENTING FREE: SIMPLER EFFECTS W/BIND (PURESCRIPT)
data ConsoleIO a
= WriteLine String a
| ReadLine (String -> a)
| Pure a
| Chain (forall z. (forall a0.
Console a0 -> (a0 -> ConsoleIO a) -> z) -> z)
FREE WHAT?
REINVENTING FREE: SIMPLER EFFECTS W/BIND (SCALA)
sealed trait ConsoleIO[A] {
def map[B](f: A => B): ConsoleIO[B] = flatMap(a => Pure[B](f(a)))
def flatMap[B](f: A => ConsoleIO[B]): ConsoleIO[B] = Chain(this, f)
}
final case class WriteLine(line: String) extends ConsoleIO[Unit]
final case class ReadLine() extends ConsoleIO[String]
final case class Pure[A](value: A) extends ConsoleIO[A]
final case class Chain[A0, A](v: ConsoleIO[A0], f: A0 => ConsoleIO[A])
extends ConsoleIO[A]
FREE WHAT?
REINVENTING FREE: SIMPLER EFFECTS W/BIND (PURESCRIPT)
data ConsoleIOF a
= WriteLine String a
| ReadLine (String -> a)
data Free f a
= Pure a
| Effect (f a)
| Chain (forall z. (
forall a0. Free f a0 -> (a0 -> Free f a) -> z) -> z)
type ConsoleIO = Free ConsoleIOF
FREE WHAT?
REINVENTING FREE: SIMPLER EFFECTS W/BIND (SCALA)
sealed trait ConsoleIOF[A]
final case class WriteLine(line: String) extends ConsoleIOF[Unit]
final case class ReadLine() extends ConsoleIOF[String]
sealed trait Free[F[_], A]
final case class Pure[F[_], A](value: A) extends Free[F, A]
final case class Effect[F[_], A](effect: F[A]) extends Free[F, A]
final case class Chain[F[_], A0, A](v: Free[A0], f: A0 => Free[A])
extends Free[F, A]
type ConsoleIO[A] = Free[ConsoleIOF, A]
FREE WHAT?
CLASSIC DEFINITION OF FREE
data Free f a = Point a | Join (f (Free f a))
sealed trait Free[F[_], A]
final case class Point[F[_], A](value: A) extends Free[F, A]
final case class Join[F[_], A](value: F[Free[F, A]]) extends Free[F, A]
FREE WHAT?
INTERPRETATION OF FREE
Free f a
Free[F, A]
^ ^ ^
|  ------- The value produced by the program
| 
|  The effects of the program
|
A program that halts, runs
forever, or produces an A
FREE WHAT?
EXAMPLE: EFFECTS
data ConsoleIO a
= ReadLine (String -> a)
| WriteLine a String
sealed trait ConsoleIO[A]
final case class ReadLine[A](next: String => A) extends ConsoleIO[A]
final case class WriteLine[A](next: A, line: String) extends ConsoleIO[A]
FREE WHAT?
EXAMPLE: HELPERS
readLine :: Free ConsoleIO String
readLine = liftF (ReadLine id)
writeLine :: String -> Free ConsoleIO Unit
writeLine = liftF <<< WriteLine unit
def readLine: Free[ConsoleIO, String] =
Free.liftF(ReadLine[String](identity))
def writeLine(line: String): Free[ConsoleIO, Unit] =
Free.liftF(WriteLine[Unit]((), line))
FREE WHAT?
EXAMPLE: PROGRAM
program = do
writeLine "What is your name?"
n <- readLine
writeLine ("Hello, " <> n <> "!")
return unit
def program: Free[ConsoleIO, Unit] =
for {
_ <- writeLine("What is your name?")
n <- readLine
_ <- writeLine("Hello, " + n + "!")
} yield ()
FREE WHAT?
COMPOSITION: FILEIO
data FileIO a
= ReadFile (Bytes -> a) String
| WriteFile a String Bytes
sealed trait FileIO[A]
final case class ReadFile[A](next: Bytes => A, name: String)
extends FileIO[A]
final case class WriteFile[A](next: A, name: String, file: Bytes)
extends FileIO[A]
FREE WHAT?
COMPOSITION: COPRODUCT
data Coproduct f g a = Left (f a) | Right (g a)
sealed trait Coproduct[F[_], G[_], A]
final case class Left[F[_], G[_], A](value: F[A])
extends Coproduct[F, G, A]
final case class Right[F[_], G[_], A](value: G[A])
extends Coproduct[F, G, A]
FREE WHAT?
COMPOSITION: PROGRAM
type Program = Free (Coproduct FileIO ConsoleIO)
type Program[A] = Free[Coproduct[FileIO, ConsoleIO, ?], A]
LIVE FREE...
TYPE-SAFE MOCKING
mockSpec :: MockSpec ConsoleIO
mockSpec = do
expectWrite _WriteLine (assertEquals "What is your name?")
expectRead _ReadLine "World"
expectWrite _WriteLine (assertEquals "Hello, World!")
def mockSpec: MockSpec[ConsoleIO] =
for {
_ <- expectWrite(_WriteLine, assertEquals("What is your name?"))
_ <- expectRead(_ReadLine, "World")
_ <- expectWrite(_WriteLine, assertEquals("Hello World"))
} yield ()
LIVE FREE...
RUNTIME OPTIMIZATION (PURESCRIPT)
data Parser a
= ParseChar (Char -> a)
| ParseString (String -> a)
| Fail String
optimize :: FreeAp Parser ~> FreeAp Parser
optimize = ...
LIVE FREE...
RUNTIME OPTIMIZATION (SCALA)
sealed trait Parser[A]
final case class ParseChar[A](next: Char => A) extends Parser[A]
final case class ParseString[A](next: String => A) extends Parser[A]
final case class Fail[A](error: String) extends Parser[A]
def optimize: FreeAp[Parser, ?] ~> FreeAp[Parser, ?] = ???
LIVE FREE...
ASPECT-ORIENTED PROGRAMMING (PURESCRIPT)
log line = liftF (Left (WriteLine unit line))
weaveLogging :: FileIO ~> Free (Coproduct ConsoleIO FileIO)
weaveLogging (ReadFile next name) = do
log $ "Reading file: " <> name
bytes <- liftF (Right (ReadFile id name))
log $ "File contents: " <> show bytes
return (next bytes)
weaveLogging (WriteFile next name bytes) = ...
program :: Free FileIO Unit
program = ...
program' :: Free (Coproduct ConsoleIO FileIO) Unit
program' = foldFree weaveLogging program
LIVE FREE...
ASPECT-ORIENTED PROGRAMMING (SCALA)
def weaveLogging: FileIO ~> Free[Coproduct[ConsoleIO, FileIO, ?], ?]
= new NaturalTransformation[FileIO, Coproduct[ConsoleIO, FileIO, ?]] {
def log(line: String) =
Free.liftF(Left[ConsoleIO, FileIO, Unit](WriteLine(unit, line)))
def apply[A](fa: FileIO[A]): Coproduct[ConsoleIO, FileIO, A] =
fa match {
case (ReadFile(next, name)) =>
for {
_ <- log("Reading file: " + name)
bytes <- liftF(Right[ConsoleIO, FileIO, Bytes](ReadFile(id, name))
_ <- log("File contents: " + bytes)
} yield next(bytes)
case (WriteFile(next, name, bytes)) =>
???
}
}
...OR DIE HARD
THE FREE MONAD IS ONLY A FREE MONAD
> Parallelism
> Failure
> Alternatives
> Nondeterminism
> ...And all other abstractions with more structure than a
monad.
...OR DIE HARD
USE CASE #1: CONCURRENCY
loadModel = do
token <- authenticate
sequential $
Model <$> parallel (get "/products/popular/" token)
<*> parallel (get "/categories/all" token)
...OR DIE HARD
USE CASE #2: NONDETERMINISM
data UI a
= Click (ClickEvent -> a)
| KeyPress (KeyEvent -> a)
| GetClass (String -> a)
| SetClass String a
| ...
doubleClick btn =
guard ((e1 e2 -> (e2.ts - e1.ts) < 200) <$> click btn <*> click btn)
toggleOnDoubleClick btn =
doubleClick btn *> toggleClass "toggled" btn
toggleFirst = foldl (e m -> m <|> toggleOnDoubleClick e) empty buttons
...OR DIE HARD
USE CASE #3: FAILURE
handleError (readConfig specifiedDir) (const $ readConfig defaultDir)
handleError(readConfig(specifiedDir),
Function.const(readConfig(defaultDir)))
HACKS FOR FREE
HACKING PARALLELISM: TYPE & EFFECT
type SeqPar f = Free (FreeAp f)
liftFA :: forall f. f ~> SeqPar f
liftFA fa = liftF (liftFreeAp fa)
type SeqPar[F[_], A] = Free[FreeAp[F, ?], A]
def liftFA[F[_], A](fa: F[A]): SeqPar[F, A] =
Free.liftF[FreeAp[F, ?], A](FreeAp.lift(fa))
HACKS FOR FREE
HACKING PARALLELISM: LIFTING PAR & SEQ
liftSeq :: forall f a. Free f a -> SeqPar f a
liftSeq = foldFree liftFA
liftPar :: forall f a. FreeAp f a -> SeqPar f a
liftPar = liftF
def liftSeq[F[_], A](freefa: Free[F, A]): SeqPar[F, A] = {
implicit val m: Monad[SeqPar[F, ?]] = Free.freeMonad[FreeAp[F, ?]]
freefa.foldMap[SeqPar[F, ?]](new NaturalTransformation[F, SeqPar[F, ?]] {
def apply[A](fa: F[A]): SeqPar[F, A] = liftFA(fa)
})
}
def liftPar[F[_], A](freeap: FreeAp[F, A]): SeqPar[F, A] =
Free.liftF[FreeAp[F, ?], A](freeap)
HACKS FOR FREE
HACKING PARALLELISM: OPTIMIZATION
type ParInterpreter f g = FreeAp f ~> g
type ParOptimizer f g = ParInterpreter f (SeqPar g)
optimize :: forall f g a. (FreeAp f ~> SeqPar g) -> SeqPar f a -> SeqPar g a
optimize = foldFree
type ParInterpreter[F[_], G[_]] = FreeAp[F, ?] ~> G
type ParOptimizer[F[_], G[_]] = ParInterpreter[F, SeqPar[G, ?]]
def optimize[F[_], G[_], A](nt: FreeAp[F, ?] ~> SeqPar[G, ?], p: SeqPar[F, A]): SeqPar[G, A] = {
implicit val m: Monad[SeqPar[G, ?]] = Free.freeMonad[FreeAp[G, ?]]
p.foldMap[SeqPar[G, ?]](nt)
}
def parOptimize[F[_], G[_], A](nt: FreeAp[F, ?] ~> FreeAp[G, ?], p: SeqPar[F, A]): SeqPar[G, A] =
optimize(new NaturalTransformation[FreeAp[F, ?], SeqPar[G, ?]] {
def apply[A](freeap: FreeAp[F, A]): SeqPar[G, A] =
liftPar(nt(freeap))
}, p)
HACKS FOR FREE
HACKING NONDETERMINISM: TYPE
data FreeAlt e f a = FreeAlt (Free (Alt e f) a)
data Alt e f a
= Failure e
| FirstSuccess (FreeAlt e f a) (FreeAlt e f a)
| Effect (f a)
final case class FreeAlt[E, F[_], A](run: Free[Alt[E, F, ?], A])
sealed trait Alt[E, F[_], A]
final case class Failure[E, F[_], A](error: E) extends Alt[E, F, A]
final case class FirstSuccess[E, F[_], A](first: FreeAlt[E, F, A],
second: FreeAlt[E, F, A], merge: (E, E) => E) extends Alt[E, F, A]
final case class Effect[E, F[_], A](effect: F[A]) extends Alt[E, F, A]
HACKS FOR FREE
HACKING NONDETERMINISM: INSTANCES
implicit def FreeAltMonadPlus[E: Monoid, F[_]]:
MonadPlus[FreeAlt[E, F, ?]] = new MonadPlus[FreeAlt[E, F, ?]] {
implicit val m: Monad[Free[Alt[E, F, ?], ?]] =
Free.freeMonad[Alt[E, F, ?]]
def point[A](a: => A): FreeAlt[E, F, A] =
FreeAlt[E, F, A](m.point(a))
def bind[A, B](fa: FreeAlt[E, F, A])(f: A => FreeAlt[E, F, B]):
FreeAlt[E, F, B] =
FreeAlt[E, F, B](m.bind(fa.run)(f.map(_.run)))
def plus[A](a: FreeAlt[E, F, A], b: => FreeAlt[E, F, A]): FreeAlt[E, F, A] =
FreeAlt(Free.liftF[Alt[E, F, ?], A](
FirstSuccess[E, F, A](a, b, Monoid[E].append(_, _))))
def empty[A]: FreeAlt[E, F, A] =
FreeAlt(Free.liftF[Alt[E, F, ?], A](Failure[E, F, A](Monoid[E].zero)))
}
HACKS FOR FREE
HACKING NONDETERMINISM: IMPROVING COMPOSABILITY
(PURESCRIPT)
data FreeAlt e f a = Free (Alt FreeAlt e f) a
data Alt t e f a
= Failure e
| FirstSuccess (t e f a) (t e f a)
| Effect (f a)
HACKS FOR FREE
HACKING NONDETERMINISM: IMPROVING COMPOSABILITY (SCALA)
final case class FreeAlt[E, F[_], A](run: Free[Alt[FreeAlt, E, F, ?], A])
sealed trait Alt[T[_, _[_], _], E, F[_], A]
final case class Failure[E, F[_], A](error: E) extends Alt[E, F, A]
final case class FirstSuccess[E, F[_], A](first: T[E, F, A],
second: T[E, F, A], merge: (E, E) => E) extends Alt[E, F, A]
final case class Effect[E, F[_], A](effect: F[A]) extends Alt[E, F, A]
HACKS FOR FREE
THE PROBLEMS WITH HACKING
> Composes poorly, and at great cost to performance, usability
data MyFree f a
= MyFree (Free (
Alt MyFree (
Parallel MyFree (
Race MyFree f))) a)
final case class MyFree[F[_], A](
run: Free[Alt[MyFree, Parallel[MyFree, Race[MyFree, F, ?], ?], ?], A])
> Blurs machinery & effects
> Where is effect? It's nested inside n-levels of machinery.
HACKS FOR FREE
WISH LIST
> Improve performance
> Improve usability
> Cleanly separate effects and machinery
RECONSTRUCTING FREE
TYPE DEFINITION (PURESCRIPT)
data FreeStar e f a
^ ^ ^
| | |
Error| Return Value
|
Effect
RECONSTRUCTING FREE
TYPE DEFINITION (SCALA)
sealed trait FreeStar[E, F[_], A]
^ ^ ^
| | |
Error | Return Value
|
Effect
RECONSTRUCTING FREE
TYPE DEFINITION (PURESCRIPT)
data FreeStar e f a
= Pure a
| Effect (f a)
| Sequence (forall z.
(forall a0.
FreeStar e f a0 -> (a0 -> FreeStar e f a) -> z) -> z)
| Parallel (forall z.
(forall l r.
FreeStar e f l -> FreeStar e f r -> (l -> r -> a) -> z) -> z)
| Failure e
| Recover (FreeStar e f a) (e -> FreeStar e f a)
| FirstSuccess (FreeStar e f a) (FreeStar e f a)
RECONSTRUCTING FREE
PURITY
final case class Pure[E, F[_], A](a: A) extends FreeStar[E, F, A]
RECONSTRUCTING FREE
EFFECTS
final case class Effect[E, F[_], A](fa: F[A]) extends FreeStar[E, F, A]
RECONSTRUCTING FREE
SEQUENCING
sealed trait Sequence[E, F[_], A] extends FreeStar[E, F, A] {
type A0
def a: FreeStar[E, F, A0]
def f: A0 => FreeStar[E, F, A]
}
RECONSTRUCTING FREE
PARALLELISM
sealed trait Parallel[E, F[_], A] extends FreeStar[E, F, A] {
type B
type C
def left: FreeStar[E, F, B]
def right: FreeStar[E, F, C]
def join: (B, C) => A
}
RECONSTRUCTING FREE
FAILURE
final case class Failure[E, F[_], A](error: E) extends FreeStar[E, F, A]
final case class Recover[E, F[_], A](
value: FreeStar[E, F, A],
f: E => FreeStar[E, F, A]) extends FreeStar[E, F, A]
RECONSTRUCTING FREE
NONDETERMINISM
final case class FirstSuccess[E, F[_], A](
first: FreeStar[E, F, A],
second: FreeStar[E, F, A]) extends FreeStar[E, F, A]
RECONSTRUCTING FREE
INSTANCES
implicit def FreeStarMonadPlus[E: Monoid, F[_]] =
new MonadPlus[FreeStar[E, F, ?]] with MonadError[FreeStar[E, F, ?], E] {
def point[A](a: => A): FreeStar[E, F, A] =
Pure[E, F, A](a)
def bind[A, B](fa: FreeStar[E, F, A])(f: A => FreeStar[E, F, B]): FreeStar[E, F, B] =
Sequence[A, E, F, B](fa, f)
def plus[A](a: FreeStar[E, F, A], b: => FreeStar[E, F, A]): FreeStar[E, F, A] =
FirstSuccess(a, b)
def empty[A]: FreeStar[E, F, A] =
Failure[E, F, A](Monoid[E].zero)
def raiseError[A](e: E): FreeStar[E, F, A] = Failure(e)
def handleError[A](fa: FreeStar[E, F, A])(f: E => FreeStar[E, F, A]): FreeStar[E, F, A] =
Recover(fa, f)
}
RECONSTRUCTING FREE
THE PROBLEMS WITH RECONSTRUCTION
> Whole program has access to all features
> Constraints (on features) liberate (interpreters)
> Liberties (on features) constrain (interpreters)
> Cannot express one feature in terms of others
> Must interpret all features at once
RECONSTRUCTING FREE
WISH LIST
> Fine-grained features — pay for what you use
> Compositional features
> Compositional interpreters
FIXING FREE
DETOUR: RECURSIVE EXPR
data Expr = Lit Int | Add Expr Expr
sealed trait Expr
final case class Lit(value: Int) extends Expr
final case class Add(left: Expr, right: Expr) extends Expr
FIXING FREE
DETOUR: FIXED EXPR
data Expr a = Lit Int | Add a a
data Fixed f = Fixed (f (Fixed f))
type RecursiveExpr = Fixed Expr
sealed trait Expr[A]
final case class Lit[A](value: Int) extends Expr[A]
final case class Add[A](left: A, right: A) extends Expr[A]
final case class Fixed[F[_]](unfix: F[Fixed[F]])
type RecursiveExpr = Fixed[Expr]
FIXING FREE
DETOUR: RECURSIVE LIST
data List a = Empty | Cons a (List a)
sealed trait List[A]
final case class Empty[A]() extends List[A]
final case class Cons[A](head: A, tail: List[A]) extends List[A]
FIXING FREE
DETOUR: FIXED LIST
data ListF z a = Empty | Cons a (z a)
data Fixed t a = Fixed (t (Fixed t) a)
type List = Fixed LiftF
sealed trait ListF[Z[_], A]
final case class Empty[Z[_], A]() extends ListF[Z, A]
final case class Cons[Z[_], A](head: A, tail: Z[A]) extends ListF[Z, A]
final case class Fixed[T[_[_], _], A](unfix: T[Fixed[T, ?], A])
type List[A] = Fixed[ListF, A]
FIXING FREE
DETOUR: FIXED LIST — EMPTY, CONS, UNCONS
empty :: List a
empty = Fixed Empty
cons :: a -> List a -> List a
cons a as = Fixed (Cons a as)
uncons :: List a -> Maybe (Tuple a List a)
uncons (Fixed Empty) = Nothing
uncons (Fixed (Cons a as)) = Just (Tuple a as)
def empty[A]: List[A] =
Fixed[ListF, A](Empty[List, A](): ListF[List, A])
def cons[A](a: A, as: List[A]): List[A] =
Fixed[ListF, A](Cons[List, A](a, as): ListF[List, A])
def uncons[A](as: List[A]): Option[(A, List[A])] = as match {
case Fixed(l) => (l : ListF[List, A]) match {
case x : Empty[List, A] => None
case x : Cons[List, A] => Some((x.head, x.tail))
}
}
FIXING FREE
DETOUR: FIXED LIST — COMPOSABLE TERMS (PURESCRIPT)
data Empty z a = Empty
data Cons z a = Cons a (z a)
data Concat z a = Concat (z a) (z a)
data Coproduct t1 t2 z a
= CLeft (t1 z a)
| CRight (t2 z a)
data Fixed t a = Fixed (t (Fixed t) a)
type ConsOrCat = Coproduct Cons Concat
type EmptyOrConsOrCat = Coproduct Empty ConsOrCat
type List a = Fixed EmptyOrConsOrCat a
FIXING FREE
DETOUR: FIXED LIST — COMPOSABLE TERMS (SCALA)
final case class Empty[Z[_], A]()
final case class Cons[Z[_], A](head: A, tail: Z[A])
final case class Concat[Z[_], A](first: Z[A], last: Z[A])
sealed trait Coproduct[T1[_[_], _], T2[_[_], _], Z[_], A]
case class CLeft[T1[_[_], _], T2[_[_], _], Z[_], A](value: T1[Z, A])
extends Coproduct[T1, T2, Z, A]
case class CRight[T1[_[_], _], T2[_[_], _], Z[_], A](value: T2[Z, A])
extends Coproduct[T1, T2, Z, A]
final case class Fixed[T[_[_], _], A](unfix: T[Fixed[T, ?], A])
type ConsOrCat[Z[_], A] = Coproduct[Cons, Concat, Z, A]
type EmptyOrConsOrCat[Z[_], A] = Coproduct[Empty, ConsOrCat, Z, A]
type List[A] = Fixed[EmptyOrConsOrCat, A]
FIXING FREE
DETOUR: FIXED LIST — COMPOSABLE TERMS (PURESCRIPT)
empty :: forall a. List a
empty = Fixed (CLeft Empty)
cons :: forall a. a -> List a -> List a
cons a as = Fixed <<< CRight <<< CLeft $ Cons a as
concat :: forall a. List a -> List a -> List a
concat a1 a2 = Fixed <<< CRight <<< CRight $ Concat a1 a2
uncons :: forall a. List a -> Maybe (Tuple a (List a))
uncons (Fixed f) = case f of
CLeft Empty -> Nothing
CRight (CLeft (Cons a as)) -> Just (Tuple a as)
CRight (CRight (Concat a1 a2)) -> case uncons a1 of
Nothing -> Nothing
Just (Tuple a as) -> Just (Tuple a (concat as a2))
FIXING FREE
DETOUR: FIXED LIST — COMPOSABLE TERMS (SCALA)
def empty[A]: List[A] =
Fixed[EmptyOrConsOrCat, A](
CLeft[Empty, ConsOrCat, List, A](Empty[List, A]()))
def cons[A](a: A, as: List[A]): List[A] =
Fixed[EmptyOrConsOrCat, A](
CRight[Empty, ConsOrCat, List, A](
CLeft[Cons, Concat, List, A](Cons[List, A](a, as))))
def concat[A](first: List[A], last: List[A]): List[A] =
Fixed[EmptyOrConsOrCat, A](
CRight[Empty, ConsOrCat, List, A](
CRight[Cons, Concat, List, A](Concat[List, A](first, last))))
def uncons[A](as: List[A]): Option[(A, List[A])] = as.unfix match {
case _ : CLeft[Empty, ConsOrCat, List, A] => None
case v : CRight[Empty, ConsOrCat, List, A] => v.value match {
case v : CLeft[Cons, Concat, List, A] => Some((v.value.head, v.value.tail))
case v : CRight[Cons, Concat, List, A] => uncons(v.value.first) match {
case None => uncons(v.value.last)
case Some((a, as)) => Some((a, concat(as, v.value.last)))
}
}
}
FIXING FREE
BASIC TERM DEFINITION
A program that halts, runs
forever, or produces an A
^
|
|
t z e a
T[Z[_], E[_], A]
^ ^ ^
| | |
| | |
Self | |
Effect |
Return
Kind: (* -> *) -> (* -> *) -> * -> *
FIXING FREE
EXTENDED TERM DEFINITION
A program that halts, errors
with an E, runs forever, or
produces an A
^
|
|
t e z e a
T[E, Z[_], E[_], A]
^ ^ ^ ^
| | | |
| | | |
| Self | |
| Effect |
| Return
Error
Kind: * -> (* -> *) -> (* -> *) -> * -> *
FIXING FREE
PURITY
data Pure e z f a = Pure a
final case class Pure[E, Z[_], F[_], A](a: A)
FIXING FREE
EFFECTS
data Effect e z f a = Effect (f a)
final case class Effect[E, Z[_], F[_], A](fa: F[A])
FIXING FREE
SEQUENCE
data Sequence e z f a
= Sequence (forall x. (forall a0. z a0 -> (a0 -> z a) -> x) -> x)
trait Sequence[E, Z[_], F[_], A] {
type A0
def a: Z[A0]
def f: A0 => Z[A]
}
FIXING FREE
PARALLEL
data Parallel e z f a
= Parallel (
forall w. (
forall l r. z l -> z r -> (l -> r -> a) -> w) -> w)
trait Parallel[E, Z[_], F[_], A] {
type B
type C
def left: Z[B]
def right: Z[C]
def join: (B, C) => A
}
FIXING FREE
FAILURE
data Failure e z f a = Failure e
data Recover e z f a = Recover (z a) (e -> z a)
case class Failure[E, Z[_], F[_], A](error: E)
case class Recover[E, Z[_], F[_], A](value: Z[A], f: E => Z[A])
FIXING FREE
ORDERED ALTERNATE
data FirstSuccess e z f a = FirstSuccess (z a) (z a)
case class FirstSuccess[E, Z[_], F[_], A](first: Z[A], second: Z[A])
FIXING FREE
TERM COMPOSITION
data EitherF t1 t2 e z f a
= LeftF (t1 e z f a)
| RightF (t1 e z f a)
sealed trait EitherF[T1[_, _[_], _[_], _], T2[_, _[_], _[_], _], E, Z[_], F[_], A]
final case class LeftF[T1[_, _[_], _[_], _], T2[_, _[_], _[_], _], E, Z[_], F[_], A](
value: T1[E, Z, F, A]) extends EitherF[T1, T2, E, Z, F, A]
final case class RightF[T1[_, _[_], _[_], _], T2[_, _[_], _[_], _], E, Z[_], F[_], A](
value: T2[E, Z, F, A]) extends EitherF[T1, T2, E, Z, F, A]
FIXING FREE
FIXING
data Fixed t e f a = Fixed (t e (Fixed t e f) f a)
final case class Fixed[T[_, _[_], _[_], _], E, F[_], A](
unfix: T[E, Fixed[T, E, F, ?], F, A]
)
FIXING FREE
THE PROBLEMS WITH FIXING
> Straining language capabilities
> "Benign" boilerplate
> But...type-level or macro machinery to the rescue?
FIXING FREE
WISH LIST
> Language-level support for positively & negatively
constrained, heterogeneous sets (unions)
> Recursion as a computational feature
> i.e. A NEW PROGRAMMING LANGUAGE
CLOSING THOUGHTS
WHERE WE ARE TODAY
> "Post-free" is about reifying the structure of computation
> By constraining the structure of subprograms, we
liberate interpretation of them
> We can do "post-free" now using a variety of
techniques
CLOSING THOUGHTS
WHERE WE COULD GO TOMORROW
> Post-free points to a world where programs are defined by:
> (a) Defining computational features in terms of others
> (b) Defining program effects in terms of others (onion
architecture)
> (c) Type-safe weaving, introspection, mocking, optimization, etc.
> (d) Purely denotational semantics for programs
THANK YOUFOLLOW ME ON TWITTER AT @JDEGOES
READ MY BLOG ON HTTP://DEGOES.NET

Más contenido relacionado

La actualidad más candente

All Aboard The Scala-to-PureScript Express!
All Aboard The Scala-to-PureScript Express!All Aboard The Scala-to-PureScript Express!
All Aboard The Scala-to-PureScript Express!John De Goes
 
Blazing Fast, Pure Effects without Monads — LambdaConf 2018
Blazing Fast, Pure Effects without Monads — LambdaConf 2018Blazing Fast, Pure Effects without Monads — LambdaConf 2018
Blazing Fast, Pure Effects without Monads — LambdaConf 2018John De Goes
 
Scalaz 8 vs Akka Actors
Scalaz 8 vs Akka ActorsScalaz 8 vs Akka Actors
Scalaz 8 vs Akka ActorsJohn De Goes
 
First-Class Patterns
First-Class PatternsFirst-Class Patterns
First-Class PatternsJohn De Goes
 
The Next Great Functional Programming Language
The Next Great Functional Programming LanguageThe Next Great Functional Programming Language
The Next Great Functional Programming LanguageJohn De Goes
 
Orthogonal Functional Architecture
Orthogonal Functional ArchitectureOrthogonal Functional Architecture
Orthogonal Functional ArchitectureJohn De Goes
 
Scalaz 8: A Whole New Game
Scalaz 8: A Whole New GameScalaz 8: A Whole New Game
Scalaz 8: A Whole New GameJohn De Goes
 
Streams for (Co)Free!
Streams for (Co)Free!Streams for (Co)Free!
Streams for (Co)Free!John De Goes
 
One Monad to Rule Them All
One Monad to Rule Them AllOne Monad to Rule Them All
One Monad to Rule Them AllJohn De Goes
 
Refactoring Functional Type Classes
Refactoring Functional Type ClassesRefactoring Functional Type Classes
Refactoring Functional Type ClassesJohn De Goes
 
Building a Tagless Final DSL for WebGL
Building a Tagless Final DSL for WebGLBuilding a Tagless Final DSL for WebGL
Building a Tagless Final DSL for WebGLLuka Jacobowitz
 
Advanced Tagless Final - Saying Farewell to Free
Advanced Tagless Final - Saying Farewell to FreeAdvanced Tagless Final - Saying Farewell to Free
Advanced Tagless Final - Saying Farewell to FreeLuka Jacobowitz
 
Atomically { Delete Your Actors }
Atomically { Delete Your Actors }Atomically { Delete Your Actors }
Atomically { Delete Your Actors }John De Goes
 
Scalaz Stream: Rebirth
Scalaz Stream: RebirthScalaz Stream: Rebirth
Scalaz Stream: RebirthJohn De Goes
 
Monad Transformers In The Wild
Monad Transformers In The WildMonad Transformers In The Wild
Monad Transformers In The WildStackMob Inc
 
Introduction to functional programming using Ocaml
Introduction to functional programming using OcamlIntroduction to functional programming using Ocaml
Introduction to functional programming using Ocamlpramode_ce
 
GUL UC3M - Introduction to functional programming
GUL UC3M - Introduction to functional programmingGUL UC3M - Introduction to functional programming
GUL UC3M - Introduction to functional programmingDavid Muñoz Díaz
 
T3chFest 2016 - The polyglot programmer
T3chFest 2016 - The polyglot programmerT3chFest 2016 - The polyglot programmer
T3chFest 2016 - The polyglot programmerDavid Muñoz Díaz
 

La actualidad más candente (20)

ZIO Queue
ZIO QueueZIO Queue
ZIO Queue
 
All Aboard The Scala-to-PureScript Express!
All Aboard The Scala-to-PureScript Express!All Aboard The Scala-to-PureScript Express!
All Aboard The Scala-to-PureScript Express!
 
Blazing Fast, Pure Effects without Monads — LambdaConf 2018
Blazing Fast, Pure Effects without Monads — LambdaConf 2018Blazing Fast, Pure Effects without Monads — LambdaConf 2018
Blazing Fast, Pure Effects without Monads — LambdaConf 2018
 
Scalaz 8 vs Akka Actors
Scalaz 8 vs Akka ActorsScalaz 8 vs Akka Actors
Scalaz 8 vs Akka Actors
 
First-Class Patterns
First-Class PatternsFirst-Class Patterns
First-Class Patterns
 
The Next Great Functional Programming Language
The Next Great Functional Programming LanguageThe Next Great Functional Programming Language
The Next Great Functional Programming Language
 
Orthogonal Functional Architecture
Orthogonal Functional ArchitectureOrthogonal Functional Architecture
Orthogonal Functional Architecture
 
Scalaz 8: A Whole New Game
Scalaz 8: A Whole New GameScalaz 8: A Whole New Game
Scalaz 8: A Whole New Game
 
Streams for (Co)Free!
Streams for (Co)Free!Streams for (Co)Free!
Streams for (Co)Free!
 
One Monad to Rule Them All
One Monad to Rule Them AllOne Monad to Rule Them All
One Monad to Rule Them All
 
Refactoring Functional Type Classes
Refactoring Functional Type ClassesRefactoring Functional Type Classes
Refactoring Functional Type Classes
 
Building a Tagless Final DSL for WebGL
Building a Tagless Final DSL for WebGLBuilding a Tagless Final DSL for WebGL
Building a Tagless Final DSL for WebGL
 
Advanced Tagless Final - Saying Farewell to Free
Advanced Tagless Final - Saying Farewell to FreeAdvanced Tagless Final - Saying Farewell to Free
Advanced Tagless Final - Saying Farewell to Free
 
Atomically { Delete Your Actors }
Atomically { Delete Your Actors }Atomically { Delete Your Actors }
Atomically { Delete Your Actors }
 
Fun with Kotlin
Fun with KotlinFun with Kotlin
Fun with Kotlin
 
Scalaz Stream: Rebirth
Scalaz Stream: RebirthScalaz Stream: Rebirth
Scalaz Stream: Rebirth
 
Monad Transformers In The Wild
Monad Transformers In The WildMonad Transformers In The Wild
Monad Transformers In The Wild
 
Introduction to functional programming using Ocaml
Introduction to functional programming using OcamlIntroduction to functional programming using Ocaml
Introduction to functional programming using Ocaml
 
GUL UC3M - Introduction to functional programming
GUL UC3M - Introduction to functional programmingGUL UC3M - Introduction to functional programming
GUL UC3M - Introduction to functional programming
 
T3chFest 2016 - The polyglot programmer
T3chFest 2016 - The polyglot programmerT3chFest 2016 - The polyglot programmer
T3chFest 2016 - The polyglot programmer
 

Similar a Post-Free: Life After Free Monads

Oh, All the things you'll traverse
Oh, All the things you'll traverseOh, All the things you'll traverse
Oh, All the things you'll traverseLuka Jacobowitz
 
Un dsl pour ma base de données
Un dsl pour ma base de donnéesUn dsl pour ma base de données
Un dsl pour ma base de donnéesRomain Lecomte
 
ZIO-Direct - Functional Scala 2022
ZIO-Direct - Functional Scala 2022ZIO-Direct - Functional Scala 2022
ZIO-Direct - Functional Scala 2022Alexander Ioffe
 
Embedding Generic Monadic Transformer into Scala. [Tfp2022]
Embedding Generic Monadic Transformer into Scala. [Tfp2022]Embedding Generic Monadic Transformer into Scala. [Tfp2022]
Embedding Generic Monadic Transformer into Scala. [Tfp2022]Ruslan Shevchenko
 
Fp in scala with adts part 2
Fp in scala with adts part 2Fp in scala with adts part 2
Fp in scala with adts part 2Hang Zhao
 
Monoids - Part 1 - with examples using Scalaz and Cats
Monoids - Part 1 - with examples using Scalaz and CatsMonoids - Part 1 - with examples using Scalaz and Cats
Monoids - Part 1 - with examples using Scalaz and CatsPhilip Schwarz
 
Taking your side effects aside
Taking your side effects asideTaking your side effects aside
Taking your side effects aside💡 Tomasz Kogut
 
Monads and friends demystified
Monads and friends demystifiedMonads and friends demystified
Monads and friends demystifiedAlessandro Lacava
 
Simple IO Monad in 'Functional Programming in Scala'
Simple IO Monad in 'Functional Programming in Scala'Simple IO Monad in 'Functional Programming in Scala'
Simple IO Monad in 'Functional Programming in Scala'Philip Schwarz
 
Concurrent Application Development using Scala
Concurrent Application Development using ScalaConcurrent Application Development using Scala
Concurrent Application Development using ScalaSiarhiej Siemianchuk
 
ZIO: Powerful and Principled Functional Programming in Scala
ZIO: Powerful and Principled Functional Programming in ScalaZIO: Powerful and Principled Functional Programming in Scala
ZIO: Powerful and Principled Functional Programming in ScalaWiem Zine Elabidine
 
Scala Functional Patterns
Scala Functional PatternsScala Functional Patterns
Scala Functional Patternsleague
 
Scala-Gopher: CSP-style programming techniques with idiomatic Scala.
Scala-Gopher: CSP-style programming techniques with idiomatic Scala.Scala-Gopher: CSP-style programming techniques with idiomatic Scala.
Scala-Gopher: CSP-style programming techniques with idiomatic Scala.Ruslan Shevchenko
 
Functions In Scala
Functions In Scala Functions In Scala
Functions In Scala Knoldus Inc.
 
Why The Free Monad isn't Free
Why The Free Monad isn't FreeWhy The Free Monad isn't Free
Why The Free Monad isn't FreeKelley Robinson
 

Similar a Post-Free: Life After Free Monads (20)

Berlin meetup
Berlin meetupBerlin meetup
Berlin meetup
 
Oh, All the things you'll traverse
Oh, All the things you'll traverseOh, All the things you'll traverse
Oh, All the things you'll traverse
 
Un dsl pour ma base de données
Un dsl pour ma base de donnéesUn dsl pour ma base de données
Un dsl pour ma base de données
 
ZIO-Direct - Functional Scala 2022
ZIO-Direct - Functional Scala 2022ZIO-Direct - Functional Scala 2022
ZIO-Direct - Functional Scala 2022
 
Embedding Generic Monadic Transformer into Scala. [Tfp2022]
Embedding Generic Monadic Transformer into Scala. [Tfp2022]Embedding Generic Monadic Transformer into Scala. [Tfp2022]
Embedding Generic Monadic Transformer into Scala. [Tfp2022]
 
Fp in scala with adts part 2
Fp in scala with adts part 2Fp in scala with adts part 2
Fp in scala with adts part 2
 
Monoids - Part 1 - with examples using Scalaz and Cats
Monoids - Part 1 - with examples using Scalaz and CatsMonoids - Part 1 - with examples using Scalaz and Cats
Monoids - Part 1 - with examples using Scalaz and Cats
 
What are monads?
What are monads?What are monads?
What are monads?
 
Taking your side effects aside
Taking your side effects asideTaking your side effects aside
Taking your side effects aside
 
Monads and friends demystified
Monads and friends demystifiedMonads and friends demystified
Monads and friends demystified
 
Simple IO Monad in 'Functional Programming in Scala'
Simple IO Monad in 'Functional Programming in Scala'Simple IO Monad in 'Functional Programming in Scala'
Simple IO Monad in 'Functional Programming in Scala'
 
Lambdaconf2019 talk
Lambdaconf2019 talkLambdaconf2019 talk
Lambdaconf2019 talk
 
Concurrent Application Development using Scala
Concurrent Application Development using ScalaConcurrent Application Development using Scala
Concurrent Application Development using Scala
 
ZIO: Powerful and Principled Functional Programming in Scala
ZIO: Powerful and Principled Functional Programming in ScalaZIO: Powerful and Principled Functional Programming in Scala
ZIO: Powerful and Principled Functional Programming in Scala
 
Scala Functional Patterns
Scala Functional PatternsScala Functional Patterns
Scala Functional Patterns
 
Scala-Gopher: CSP-style programming techniques with idiomatic Scala.
Scala-Gopher: CSP-style programming techniques with idiomatic Scala.Scala-Gopher: CSP-style programming techniques with idiomatic Scala.
Scala-Gopher: CSP-style programming techniques with idiomatic Scala.
 
Ray tracing with ZIO-ZLayer
Ray tracing with ZIO-ZLayerRay tracing with ZIO-ZLayer
Ray tracing with ZIO-ZLayer
 
Functions In Scala
Functions In Scala Functions In Scala
Functions In Scala
 
Why The Free Monad isn't Free
Why The Free Monad isn't FreeWhy The Free Monad isn't Free
Why The Free Monad isn't Free
 
From OOP To FP Through A Practical Case
From OOP To FP Through A Practical CaseFrom OOP To FP Through A Practical Case
From OOP To FP Through A Practical Case
 

Más de John De Goes

Error Management: Future vs ZIO
Error Management: Future vs ZIOError Management: Future vs ZIO
Error Management: Future vs ZIOJohn De Goes
 
Scalaz Stream: Rebirth
Scalaz Stream: RebirthScalaz Stream: Rebirth
Scalaz Stream: RebirthJohn De Goes
 
Getting Started with PureScript
Getting Started with PureScriptGetting Started with PureScript
Getting Started with PureScriptJohn De Goes
 
SlamData - How MongoDB Is Powering a Revolution in Visual Analytics
SlamData - How MongoDB Is Powering a Revolution in Visual AnalyticsSlamData - How MongoDB Is Powering a Revolution in Visual Analytics
SlamData - How MongoDB Is Powering a Revolution in Visual AnalyticsJohn De Goes
 
The Dark Side of NoSQL
The Dark Side of NoSQLThe Dark Side of NoSQL
The Dark Side of NoSQLJohn De Goes
 
Quirrel & R for Dummies
Quirrel & R for DummiesQuirrel & R for Dummies
Quirrel & R for DummiesJohn De Goes
 
In-Database Predictive Analytics
In-Database Predictive AnalyticsIn-Database Predictive Analytics
In-Database Predictive AnalyticsJohn De Goes
 
Analytics Maturity Model
Analytics Maturity ModelAnalytics Maturity Model
Analytics Maturity ModelJohn De Goes
 
Rise of the scientific database
Rise of the scientific databaseRise of the scientific database
Rise of the scientific databaseJohn De Goes
 

Más de John De Goes (10)

Error Management: Future vs ZIO
Error Management: Future vs ZIOError Management: Future vs ZIO
Error Management: Future vs ZIO
 
Scalaz Stream: Rebirth
Scalaz Stream: RebirthScalaz Stream: Rebirth
Scalaz Stream: Rebirth
 
Getting Started with PureScript
Getting Started with PureScriptGetting Started with PureScript
Getting Started with PureScript
 
SlamData - How MongoDB Is Powering a Revolution in Visual Analytics
SlamData - How MongoDB Is Powering a Revolution in Visual AnalyticsSlamData - How MongoDB Is Powering a Revolution in Visual Analytics
SlamData - How MongoDB Is Powering a Revolution in Visual Analytics
 
The Dark Side of NoSQL
The Dark Side of NoSQLThe Dark Side of NoSQL
The Dark Side of NoSQL
 
Quirrel & R for Dummies
Quirrel & R for DummiesQuirrel & R for Dummies
Quirrel & R for Dummies
 
In-Database Predictive Analytics
In-Database Predictive AnalyticsIn-Database Predictive Analytics
In-Database Predictive Analytics
 
Analytics Maturity Model
Analytics Maturity ModelAnalytics Maturity Model
Analytics Maturity Model
 
Rise of the scientific database
Rise of the scientific databaseRise of the scientific database
Rise of the scientific database
 
Fun with automata
Fun with automataFun with automata
Fun with automata
 

Último

DevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platformsDevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platformsSergiu Bodiu
 
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024BookNet Canada
 
Commit 2024 - Secret Management made easy
Commit 2024 - Secret Management made easyCommit 2024 - Secret Management made easy
Commit 2024 - Secret Management made easyAlfredo García Lavilla
 
Leverage Zilliz Serverless - Up to 50X Saving for Your Vector Storage Cost
Leverage Zilliz Serverless - Up to 50X Saving for Your Vector Storage CostLeverage Zilliz Serverless - Up to 50X Saving for Your Vector Storage Cost
Leverage Zilliz Serverless - Up to 50X Saving for Your Vector Storage CostZilliz
 
Unraveling Multimodality with Large Language Models.pdf
Unraveling Multimodality with Large Language Models.pdfUnraveling Multimodality with Large Language Models.pdf
Unraveling Multimodality with Large Language Models.pdfAlex Barbosa Coqueiro
 
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks..."LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...Fwdays
 
From Family Reminiscence to Scholarly Archive .
From Family Reminiscence to Scholarly Archive .From Family Reminiscence to Scholarly Archive .
From Family Reminiscence to Scholarly Archive .Alan Dix
 
Designing IA for AI - Information Architecture Conference 2024
Designing IA for AI - Information Architecture Conference 2024Designing IA for AI - Information Architecture Conference 2024
Designing IA for AI - Information Architecture Conference 2024Enterprise Knowledge
 
Story boards and shot lists for my a level piece
Story boards and shot lists for my a level pieceStory boards and shot lists for my a level piece
Story boards and shot lists for my a level piececharlottematthew16
 
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024BookNet Canada
 
Anypoint Exchange: It’s Not Just a Repo!
Anypoint Exchange: It’s Not Just a Repo!Anypoint Exchange: It’s Not Just a Repo!
Anypoint Exchange: It’s Not Just a Repo!Manik S Magar
 
Powerpoint exploring the locations used in television show Time Clash
Powerpoint exploring the locations used in television show Time ClashPowerpoint exploring the locations used in television show Time Clash
Powerpoint exploring the locations used in television show Time Clashcharlottematthew16
 
Scanning the Internet for External Cloud Exposures via SSL Certs
Scanning the Internet for External Cloud Exposures via SSL CertsScanning the Internet for External Cloud Exposures via SSL Certs
Scanning the Internet for External Cloud Exposures via SSL CertsRizwan Syed
 
Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 365Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 3652toLead Limited
 
H2O.ai CEO/Founder: Sri Ambati Keynote at Wells Fargo Day
H2O.ai CEO/Founder: Sri Ambati Keynote at Wells Fargo DayH2O.ai CEO/Founder: Sri Ambati Keynote at Wells Fargo Day
H2O.ai CEO/Founder: Sri Ambati Keynote at Wells Fargo DaySri Ambati
 
Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024Scott Keck-Warren
 
SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024Lorenzo Miniero
 
Search Engine Optimization SEO PDF for 2024.pdf
Search Engine Optimization SEO PDF for 2024.pdfSearch Engine Optimization SEO PDF for 2024.pdf
Search Engine Optimization SEO PDF for 2024.pdfRankYa
 
Connect Wave/ connectwave Pitch Deck Presentation
Connect Wave/ connectwave Pitch Deck PresentationConnect Wave/ connectwave Pitch Deck Presentation
Connect Wave/ connectwave Pitch Deck PresentationSlibray Presentation
 
DSPy a system for AI to Write Prompts and Do Fine Tuning
DSPy a system for AI to Write Prompts and Do Fine TuningDSPy a system for AI to Write Prompts and Do Fine Tuning
DSPy a system for AI to Write Prompts and Do Fine TuningLars Bell
 

Último (20)

DevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platformsDevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platforms
 
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
 
Commit 2024 - Secret Management made easy
Commit 2024 - Secret Management made easyCommit 2024 - Secret Management made easy
Commit 2024 - Secret Management made easy
 
Leverage Zilliz Serverless - Up to 50X Saving for Your Vector Storage Cost
Leverage Zilliz Serverless - Up to 50X Saving for Your Vector Storage CostLeverage Zilliz Serverless - Up to 50X Saving for Your Vector Storage Cost
Leverage Zilliz Serverless - Up to 50X Saving for Your Vector Storage Cost
 
Unraveling Multimodality with Large Language Models.pdf
Unraveling Multimodality with Large Language Models.pdfUnraveling Multimodality with Large Language Models.pdf
Unraveling Multimodality with Large Language Models.pdf
 
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks..."LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
 
From Family Reminiscence to Scholarly Archive .
From Family Reminiscence to Scholarly Archive .From Family Reminiscence to Scholarly Archive .
From Family Reminiscence to Scholarly Archive .
 
Designing IA for AI - Information Architecture Conference 2024
Designing IA for AI - Information Architecture Conference 2024Designing IA for AI - Information Architecture Conference 2024
Designing IA for AI - Information Architecture Conference 2024
 
Story boards and shot lists for my a level piece
Story boards and shot lists for my a level pieceStory boards and shot lists for my a level piece
Story boards and shot lists for my a level piece
 
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
 
Anypoint Exchange: It’s Not Just a Repo!
Anypoint Exchange: It’s Not Just a Repo!Anypoint Exchange: It’s Not Just a Repo!
Anypoint Exchange: It’s Not Just a Repo!
 
Powerpoint exploring the locations used in television show Time Clash
Powerpoint exploring the locations used in television show Time ClashPowerpoint exploring the locations used in television show Time Clash
Powerpoint exploring the locations used in television show Time Clash
 
Scanning the Internet for External Cloud Exposures via SSL Certs
Scanning the Internet for External Cloud Exposures via SSL CertsScanning the Internet for External Cloud Exposures via SSL Certs
Scanning the Internet for External Cloud Exposures via SSL Certs
 
Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 365Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 365
 
H2O.ai CEO/Founder: Sri Ambati Keynote at Wells Fargo Day
H2O.ai CEO/Founder: Sri Ambati Keynote at Wells Fargo DayH2O.ai CEO/Founder: Sri Ambati Keynote at Wells Fargo Day
H2O.ai CEO/Founder: Sri Ambati Keynote at Wells Fargo Day
 
Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024
 
SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024
 
Search Engine Optimization SEO PDF for 2024.pdf
Search Engine Optimization SEO PDF for 2024.pdfSearch Engine Optimization SEO PDF for 2024.pdf
Search Engine Optimization SEO PDF for 2024.pdf
 
Connect Wave/ connectwave Pitch Deck Presentation
Connect Wave/ connectwave Pitch Deck PresentationConnect Wave/ connectwave Pitch Deck Presentation
Connect Wave/ connectwave Pitch Deck Presentation
 
DSPy a system for AI to Write Prompts and Do Fine Tuning
DSPy a system for AI to Write Prompts and Do Fine TuningDSPy a system for AI to Write Prompts and Do Fine Tuning
DSPy a system for AI to Write Prompts and Do Fine Tuning
 

Post-Free: Life After Free Monads

  • 1. POST-FREE: LIFE AFTER FREE MONADSJOHN A. DE GOES — @JDEGOES
  • 2. OUTLINE > Free What? > Live Free... > ...Or Die Hard > Exploration of Solutions > Hacks for Free > Reconstructing Free > Fixing Free > Closing Thoughts
  • 3. FREE WHAT? REINVENTING FREE: PURE EFFECTS data ConsoleIO = WriteLine String ConsoleIO | ReadLine (String -> ConsoleIO) | End sealed trait ConsoleIO final case class WriteLine(line: String, then: ConsoleIO) extends ConsoleIO final case class ReadLine(process: String => ConsoleIO) extends ConsoleIO final case object End extends ConsoleIO
  • 4. FREE WHAT? REINVENTING FREE: PURE EFFECTS W/RETURNS data ConsoleIO a = WriteLine String (ConsoleIO a) | ReadLine (String -> ConsoleIO a) | EndWith a sealed trait ConsoleIO[A] final case class WriteLine[A](line: String, then: ConsoleIO[A]) extends ConsoleIO[A] final case class ReadLine[A](process: String => ConsoleIO[A]) extends ConsoleIO[A] final case class EndWith[A](value: A) extends ConsoleIO[A]
  • 5. FREE WHAT? REINVENTING FREE: PURE EFFECTS W/MAP (PURESCRIPT) data ConsoleIO a = WriteLine String (ConsoleIO a) | ReadLine (String -> ConsoleIO a) | EndWith a | Map (forall z. (forall a0. ConsoleIO a0 -> (a0 -> a) -> z) -> z)
  • 6. FREE WHAT? REINVENTING FREE: PURE EFFECTS W/MAP (SCALA) sealed trait ConsoleIO[A] { def map[B](f: A => B): Console[B] = Map(this, f) } final case class WriteLine[A](line: String, then: ConsoleIO[A]) extends ConsoleIO[A] final case class ReadLine[A](process: String => ConsoleIO[A]) extends ConsoleIO[A] final case class EndWith[A](value: A) extends ConsoleIO[A] final case class Map[A0, A](v: ConsoleIO[A0], f: A0 => A) extends ConsoleIO[A]
  • 7. FREE WHAT? REINVENTING FREE: SIMPLER EFFECTS W/BIND (PURESCRIPT) data ConsoleIO a = WriteLine String a | ReadLine (String -> a) | Pure a | Chain (forall z. (forall a0. Console a0 -> (a0 -> ConsoleIO a) -> z) -> z)
  • 8. FREE WHAT? REINVENTING FREE: SIMPLER EFFECTS W/BIND (SCALA) sealed trait ConsoleIO[A] { def map[B](f: A => B): ConsoleIO[B] = flatMap(a => Pure[B](f(a))) def flatMap[B](f: A => ConsoleIO[B]): ConsoleIO[B] = Chain(this, f) } final case class WriteLine(line: String) extends ConsoleIO[Unit] final case class ReadLine() extends ConsoleIO[String] final case class Pure[A](value: A) extends ConsoleIO[A] final case class Chain[A0, A](v: ConsoleIO[A0], f: A0 => ConsoleIO[A]) extends ConsoleIO[A]
  • 9. FREE WHAT? REINVENTING FREE: SIMPLER EFFECTS W/BIND (PURESCRIPT) data ConsoleIOF a = WriteLine String a | ReadLine (String -> a) data Free f a = Pure a | Effect (f a) | Chain (forall z. ( forall a0. Free f a0 -> (a0 -> Free f a) -> z) -> z) type ConsoleIO = Free ConsoleIOF
  • 10. FREE WHAT? REINVENTING FREE: SIMPLER EFFECTS W/BIND (SCALA) sealed trait ConsoleIOF[A] final case class WriteLine(line: String) extends ConsoleIOF[Unit] final case class ReadLine() extends ConsoleIOF[String] sealed trait Free[F[_], A] final case class Pure[F[_], A](value: A) extends Free[F, A] final case class Effect[F[_], A](effect: F[A]) extends Free[F, A] final case class Chain[F[_], A0, A](v: Free[A0], f: A0 => Free[A]) extends Free[F, A] type ConsoleIO[A] = Free[ConsoleIOF, A]
  • 11. FREE WHAT? CLASSIC DEFINITION OF FREE data Free f a = Point a | Join (f (Free f a)) sealed trait Free[F[_], A] final case class Point[F[_], A](value: A) extends Free[F, A] final case class Join[F[_], A](value: F[Free[F, A]]) extends Free[F, A]
  • 12. FREE WHAT? INTERPRETATION OF FREE Free f a Free[F, A] ^ ^ ^ | ------- The value produced by the program | | The effects of the program | A program that halts, runs forever, or produces an A
  • 13. FREE WHAT? EXAMPLE: EFFECTS data ConsoleIO a = ReadLine (String -> a) | WriteLine a String sealed trait ConsoleIO[A] final case class ReadLine[A](next: String => A) extends ConsoleIO[A] final case class WriteLine[A](next: A, line: String) extends ConsoleIO[A]
  • 14. FREE WHAT? EXAMPLE: HELPERS readLine :: Free ConsoleIO String readLine = liftF (ReadLine id) writeLine :: String -> Free ConsoleIO Unit writeLine = liftF <<< WriteLine unit def readLine: Free[ConsoleIO, String] = Free.liftF(ReadLine[String](identity)) def writeLine(line: String): Free[ConsoleIO, Unit] = Free.liftF(WriteLine[Unit]((), line))
  • 15. FREE WHAT? EXAMPLE: PROGRAM program = do writeLine "What is your name?" n <- readLine writeLine ("Hello, " <> n <> "!") return unit def program: Free[ConsoleIO, Unit] = for { _ <- writeLine("What is your name?") n <- readLine _ <- writeLine("Hello, " + n + "!") } yield ()
  • 16. FREE WHAT? COMPOSITION: FILEIO data FileIO a = ReadFile (Bytes -> a) String | WriteFile a String Bytes sealed trait FileIO[A] final case class ReadFile[A](next: Bytes => A, name: String) extends FileIO[A] final case class WriteFile[A](next: A, name: String, file: Bytes) extends FileIO[A]
  • 17. FREE WHAT? COMPOSITION: COPRODUCT data Coproduct f g a = Left (f a) | Right (g a) sealed trait Coproduct[F[_], G[_], A] final case class Left[F[_], G[_], A](value: F[A]) extends Coproduct[F, G, A] final case class Right[F[_], G[_], A](value: G[A]) extends Coproduct[F, G, A]
  • 18. FREE WHAT? COMPOSITION: PROGRAM type Program = Free (Coproduct FileIO ConsoleIO) type Program[A] = Free[Coproduct[FileIO, ConsoleIO, ?], A]
  • 19. LIVE FREE... TYPE-SAFE MOCKING mockSpec :: MockSpec ConsoleIO mockSpec = do expectWrite _WriteLine (assertEquals "What is your name?") expectRead _ReadLine "World" expectWrite _WriteLine (assertEquals "Hello, World!") def mockSpec: MockSpec[ConsoleIO] = for { _ <- expectWrite(_WriteLine, assertEquals("What is your name?")) _ <- expectRead(_ReadLine, "World") _ <- expectWrite(_WriteLine, assertEquals("Hello World")) } yield ()
  • 20. LIVE FREE... RUNTIME OPTIMIZATION (PURESCRIPT) data Parser a = ParseChar (Char -> a) | ParseString (String -> a) | Fail String optimize :: FreeAp Parser ~> FreeAp Parser optimize = ...
  • 21. LIVE FREE... RUNTIME OPTIMIZATION (SCALA) sealed trait Parser[A] final case class ParseChar[A](next: Char => A) extends Parser[A] final case class ParseString[A](next: String => A) extends Parser[A] final case class Fail[A](error: String) extends Parser[A] def optimize: FreeAp[Parser, ?] ~> FreeAp[Parser, ?] = ???
  • 22. LIVE FREE... ASPECT-ORIENTED PROGRAMMING (PURESCRIPT) log line = liftF (Left (WriteLine unit line)) weaveLogging :: FileIO ~> Free (Coproduct ConsoleIO FileIO) weaveLogging (ReadFile next name) = do log $ "Reading file: " <> name bytes <- liftF (Right (ReadFile id name)) log $ "File contents: " <> show bytes return (next bytes) weaveLogging (WriteFile next name bytes) = ... program :: Free FileIO Unit program = ... program' :: Free (Coproduct ConsoleIO FileIO) Unit program' = foldFree weaveLogging program
  • 23. LIVE FREE... ASPECT-ORIENTED PROGRAMMING (SCALA) def weaveLogging: FileIO ~> Free[Coproduct[ConsoleIO, FileIO, ?], ?] = new NaturalTransformation[FileIO, Coproduct[ConsoleIO, FileIO, ?]] { def log(line: String) = Free.liftF(Left[ConsoleIO, FileIO, Unit](WriteLine(unit, line))) def apply[A](fa: FileIO[A]): Coproduct[ConsoleIO, FileIO, A] = fa match { case (ReadFile(next, name)) => for { _ <- log("Reading file: " + name) bytes <- liftF(Right[ConsoleIO, FileIO, Bytes](ReadFile(id, name)) _ <- log("File contents: " + bytes) } yield next(bytes) case (WriteFile(next, name, bytes)) => ??? } }
  • 24. ...OR DIE HARD THE FREE MONAD IS ONLY A FREE MONAD > Parallelism > Failure > Alternatives > Nondeterminism > ...And all other abstractions with more structure than a monad.
  • 25. ...OR DIE HARD USE CASE #1: CONCURRENCY loadModel = do token <- authenticate sequential $ Model <$> parallel (get "/products/popular/" token) <*> parallel (get "/categories/all" token)
  • 26. ...OR DIE HARD USE CASE #2: NONDETERMINISM data UI a = Click (ClickEvent -> a) | KeyPress (KeyEvent -> a) | GetClass (String -> a) | SetClass String a | ... doubleClick btn = guard ((e1 e2 -> (e2.ts - e1.ts) < 200) <$> click btn <*> click btn) toggleOnDoubleClick btn = doubleClick btn *> toggleClass "toggled" btn toggleFirst = foldl (e m -> m <|> toggleOnDoubleClick e) empty buttons
  • 27. ...OR DIE HARD USE CASE #3: FAILURE handleError (readConfig specifiedDir) (const $ readConfig defaultDir) handleError(readConfig(specifiedDir), Function.const(readConfig(defaultDir)))
  • 28. HACKS FOR FREE HACKING PARALLELISM: TYPE & EFFECT type SeqPar f = Free (FreeAp f) liftFA :: forall f. f ~> SeqPar f liftFA fa = liftF (liftFreeAp fa) type SeqPar[F[_], A] = Free[FreeAp[F, ?], A] def liftFA[F[_], A](fa: F[A]): SeqPar[F, A] = Free.liftF[FreeAp[F, ?], A](FreeAp.lift(fa))
  • 29. HACKS FOR FREE HACKING PARALLELISM: LIFTING PAR & SEQ liftSeq :: forall f a. Free f a -> SeqPar f a liftSeq = foldFree liftFA liftPar :: forall f a. FreeAp f a -> SeqPar f a liftPar = liftF def liftSeq[F[_], A](freefa: Free[F, A]): SeqPar[F, A] = { implicit val m: Monad[SeqPar[F, ?]] = Free.freeMonad[FreeAp[F, ?]] freefa.foldMap[SeqPar[F, ?]](new NaturalTransformation[F, SeqPar[F, ?]] { def apply[A](fa: F[A]): SeqPar[F, A] = liftFA(fa) }) } def liftPar[F[_], A](freeap: FreeAp[F, A]): SeqPar[F, A] = Free.liftF[FreeAp[F, ?], A](freeap)
  • 30. HACKS FOR FREE HACKING PARALLELISM: OPTIMIZATION type ParInterpreter f g = FreeAp f ~> g type ParOptimizer f g = ParInterpreter f (SeqPar g) optimize :: forall f g a. (FreeAp f ~> SeqPar g) -> SeqPar f a -> SeqPar g a optimize = foldFree type ParInterpreter[F[_], G[_]] = FreeAp[F, ?] ~> G type ParOptimizer[F[_], G[_]] = ParInterpreter[F, SeqPar[G, ?]] def optimize[F[_], G[_], A](nt: FreeAp[F, ?] ~> SeqPar[G, ?], p: SeqPar[F, A]): SeqPar[G, A] = { implicit val m: Monad[SeqPar[G, ?]] = Free.freeMonad[FreeAp[G, ?]] p.foldMap[SeqPar[G, ?]](nt) } def parOptimize[F[_], G[_], A](nt: FreeAp[F, ?] ~> FreeAp[G, ?], p: SeqPar[F, A]): SeqPar[G, A] = optimize(new NaturalTransformation[FreeAp[F, ?], SeqPar[G, ?]] { def apply[A](freeap: FreeAp[F, A]): SeqPar[G, A] = liftPar(nt(freeap)) }, p)
  • 31. HACKS FOR FREE HACKING NONDETERMINISM: TYPE data FreeAlt e f a = FreeAlt (Free (Alt e f) a) data Alt e f a = Failure e | FirstSuccess (FreeAlt e f a) (FreeAlt e f a) | Effect (f a) final case class FreeAlt[E, F[_], A](run: Free[Alt[E, F, ?], A]) sealed trait Alt[E, F[_], A] final case class Failure[E, F[_], A](error: E) extends Alt[E, F, A] final case class FirstSuccess[E, F[_], A](first: FreeAlt[E, F, A], second: FreeAlt[E, F, A], merge: (E, E) => E) extends Alt[E, F, A] final case class Effect[E, F[_], A](effect: F[A]) extends Alt[E, F, A]
  • 32. HACKS FOR FREE HACKING NONDETERMINISM: INSTANCES implicit def FreeAltMonadPlus[E: Monoid, F[_]]: MonadPlus[FreeAlt[E, F, ?]] = new MonadPlus[FreeAlt[E, F, ?]] { implicit val m: Monad[Free[Alt[E, F, ?], ?]] = Free.freeMonad[Alt[E, F, ?]] def point[A](a: => A): FreeAlt[E, F, A] = FreeAlt[E, F, A](m.point(a)) def bind[A, B](fa: FreeAlt[E, F, A])(f: A => FreeAlt[E, F, B]): FreeAlt[E, F, B] = FreeAlt[E, F, B](m.bind(fa.run)(f.map(_.run))) def plus[A](a: FreeAlt[E, F, A], b: => FreeAlt[E, F, A]): FreeAlt[E, F, A] = FreeAlt(Free.liftF[Alt[E, F, ?], A]( FirstSuccess[E, F, A](a, b, Monoid[E].append(_, _)))) def empty[A]: FreeAlt[E, F, A] = FreeAlt(Free.liftF[Alt[E, F, ?], A](Failure[E, F, A](Monoid[E].zero))) }
  • 33. HACKS FOR FREE HACKING NONDETERMINISM: IMPROVING COMPOSABILITY (PURESCRIPT) data FreeAlt e f a = Free (Alt FreeAlt e f) a data Alt t e f a = Failure e | FirstSuccess (t e f a) (t e f a) | Effect (f a)
  • 34. HACKS FOR FREE HACKING NONDETERMINISM: IMPROVING COMPOSABILITY (SCALA) final case class FreeAlt[E, F[_], A](run: Free[Alt[FreeAlt, E, F, ?], A]) sealed trait Alt[T[_, _[_], _], E, F[_], A] final case class Failure[E, F[_], A](error: E) extends Alt[E, F, A] final case class FirstSuccess[E, F[_], A](first: T[E, F, A], second: T[E, F, A], merge: (E, E) => E) extends Alt[E, F, A] final case class Effect[E, F[_], A](effect: F[A]) extends Alt[E, F, A]
  • 35. HACKS FOR FREE THE PROBLEMS WITH HACKING > Composes poorly, and at great cost to performance, usability data MyFree f a = MyFree (Free ( Alt MyFree ( Parallel MyFree ( Race MyFree f))) a) final case class MyFree[F[_], A]( run: Free[Alt[MyFree, Parallel[MyFree, Race[MyFree, F, ?], ?], ?], A]) > Blurs machinery & effects > Where is effect? It's nested inside n-levels of machinery.
  • 36. HACKS FOR FREE WISH LIST > Improve performance > Improve usability > Cleanly separate effects and machinery
  • 37. RECONSTRUCTING FREE TYPE DEFINITION (PURESCRIPT) data FreeStar e f a ^ ^ ^ | | | Error| Return Value | Effect
  • 38. RECONSTRUCTING FREE TYPE DEFINITION (SCALA) sealed trait FreeStar[E, F[_], A] ^ ^ ^ | | | Error | Return Value | Effect
  • 39. RECONSTRUCTING FREE TYPE DEFINITION (PURESCRIPT) data FreeStar e f a = Pure a | Effect (f a) | Sequence (forall z. (forall a0. FreeStar e f a0 -> (a0 -> FreeStar e f a) -> z) -> z) | Parallel (forall z. (forall l r. FreeStar e f l -> FreeStar e f r -> (l -> r -> a) -> z) -> z) | Failure e | Recover (FreeStar e f a) (e -> FreeStar e f a) | FirstSuccess (FreeStar e f a) (FreeStar e f a)
  • 40. RECONSTRUCTING FREE PURITY final case class Pure[E, F[_], A](a: A) extends FreeStar[E, F, A]
  • 41. RECONSTRUCTING FREE EFFECTS final case class Effect[E, F[_], A](fa: F[A]) extends FreeStar[E, F, A]
  • 42. RECONSTRUCTING FREE SEQUENCING sealed trait Sequence[E, F[_], A] extends FreeStar[E, F, A] { type A0 def a: FreeStar[E, F, A0] def f: A0 => FreeStar[E, F, A] }
  • 43. RECONSTRUCTING FREE PARALLELISM sealed trait Parallel[E, F[_], A] extends FreeStar[E, F, A] { type B type C def left: FreeStar[E, F, B] def right: FreeStar[E, F, C] def join: (B, C) => A }
  • 44. RECONSTRUCTING FREE FAILURE final case class Failure[E, F[_], A](error: E) extends FreeStar[E, F, A] final case class Recover[E, F[_], A]( value: FreeStar[E, F, A], f: E => FreeStar[E, F, A]) extends FreeStar[E, F, A]
  • 45. RECONSTRUCTING FREE NONDETERMINISM final case class FirstSuccess[E, F[_], A]( first: FreeStar[E, F, A], second: FreeStar[E, F, A]) extends FreeStar[E, F, A]
  • 46. RECONSTRUCTING FREE INSTANCES implicit def FreeStarMonadPlus[E: Monoid, F[_]] = new MonadPlus[FreeStar[E, F, ?]] with MonadError[FreeStar[E, F, ?], E] { def point[A](a: => A): FreeStar[E, F, A] = Pure[E, F, A](a) def bind[A, B](fa: FreeStar[E, F, A])(f: A => FreeStar[E, F, B]): FreeStar[E, F, B] = Sequence[A, E, F, B](fa, f) def plus[A](a: FreeStar[E, F, A], b: => FreeStar[E, F, A]): FreeStar[E, F, A] = FirstSuccess(a, b) def empty[A]: FreeStar[E, F, A] = Failure[E, F, A](Monoid[E].zero) def raiseError[A](e: E): FreeStar[E, F, A] = Failure(e) def handleError[A](fa: FreeStar[E, F, A])(f: E => FreeStar[E, F, A]): FreeStar[E, F, A] = Recover(fa, f) }
  • 47. RECONSTRUCTING FREE THE PROBLEMS WITH RECONSTRUCTION > Whole program has access to all features > Constraints (on features) liberate (interpreters) > Liberties (on features) constrain (interpreters) > Cannot express one feature in terms of others > Must interpret all features at once
  • 48. RECONSTRUCTING FREE WISH LIST > Fine-grained features — pay for what you use > Compositional features > Compositional interpreters
  • 49. FIXING FREE DETOUR: RECURSIVE EXPR data Expr = Lit Int | Add Expr Expr sealed trait Expr final case class Lit(value: Int) extends Expr final case class Add(left: Expr, right: Expr) extends Expr
  • 50. FIXING FREE DETOUR: FIXED EXPR data Expr a = Lit Int | Add a a data Fixed f = Fixed (f (Fixed f)) type RecursiveExpr = Fixed Expr sealed trait Expr[A] final case class Lit[A](value: Int) extends Expr[A] final case class Add[A](left: A, right: A) extends Expr[A] final case class Fixed[F[_]](unfix: F[Fixed[F]]) type RecursiveExpr = Fixed[Expr]
  • 51. FIXING FREE DETOUR: RECURSIVE LIST data List a = Empty | Cons a (List a) sealed trait List[A] final case class Empty[A]() extends List[A] final case class Cons[A](head: A, tail: List[A]) extends List[A]
  • 52. FIXING FREE DETOUR: FIXED LIST data ListF z a = Empty | Cons a (z a) data Fixed t a = Fixed (t (Fixed t) a) type List = Fixed LiftF sealed trait ListF[Z[_], A] final case class Empty[Z[_], A]() extends ListF[Z, A] final case class Cons[Z[_], A](head: A, tail: Z[A]) extends ListF[Z, A] final case class Fixed[T[_[_], _], A](unfix: T[Fixed[T, ?], A]) type List[A] = Fixed[ListF, A]
  • 53. FIXING FREE DETOUR: FIXED LIST — EMPTY, CONS, UNCONS empty :: List a empty = Fixed Empty cons :: a -> List a -> List a cons a as = Fixed (Cons a as) uncons :: List a -> Maybe (Tuple a List a) uncons (Fixed Empty) = Nothing uncons (Fixed (Cons a as)) = Just (Tuple a as) def empty[A]: List[A] = Fixed[ListF, A](Empty[List, A](): ListF[List, A]) def cons[A](a: A, as: List[A]): List[A] = Fixed[ListF, A](Cons[List, A](a, as): ListF[List, A]) def uncons[A](as: List[A]): Option[(A, List[A])] = as match { case Fixed(l) => (l : ListF[List, A]) match { case x : Empty[List, A] => None case x : Cons[List, A] => Some((x.head, x.tail)) } }
  • 54. FIXING FREE DETOUR: FIXED LIST — COMPOSABLE TERMS (PURESCRIPT) data Empty z a = Empty data Cons z a = Cons a (z a) data Concat z a = Concat (z a) (z a) data Coproduct t1 t2 z a = CLeft (t1 z a) | CRight (t2 z a) data Fixed t a = Fixed (t (Fixed t) a) type ConsOrCat = Coproduct Cons Concat type EmptyOrConsOrCat = Coproduct Empty ConsOrCat type List a = Fixed EmptyOrConsOrCat a
  • 55. FIXING FREE DETOUR: FIXED LIST — COMPOSABLE TERMS (SCALA) final case class Empty[Z[_], A]() final case class Cons[Z[_], A](head: A, tail: Z[A]) final case class Concat[Z[_], A](first: Z[A], last: Z[A]) sealed trait Coproduct[T1[_[_], _], T2[_[_], _], Z[_], A] case class CLeft[T1[_[_], _], T2[_[_], _], Z[_], A](value: T1[Z, A]) extends Coproduct[T1, T2, Z, A] case class CRight[T1[_[_], _], T2[_[_], _], Z[_], A](value: T2[Z, A]) extends Coproduct[T1, T2, Z, A] final case class Fixed[T[_[_], _], A](unfix: T[Fixed[T, ?], A]) type ConsOrCat[Z[_], A] = Coproduct[Cons, Concat, Z, A] type EmptyOrConsOrCat[Z[_], A] = Coproduct[Empty, ConsOrCat, Z, A] type List[A] = Fixed[EmptyOrConsOrCat, A]
  • 56. FIXING FREE DETOUR: FIXED LIST — COMPOSABLE TERMS (PURESCRIPT) empty :: forall a. List a empty = Fixed (CLeft Empty) cons :: forall a. a -> List a -> List a cons a as = Fixed <<< CRight <<< CLeft $ Cons a as concat :: forall a. List a -> List a -> List a concat a1 a2 = Fixed <<< CRight <<< CRight $ Concat a1 a2 uncons :: forall a. List a -> Maybe (Tuple a (List a)) uncons (Fixed f) = case f of CLeft Empty -> Nothing CRight (CLeft (Cons a as)) -> Just (Tuple a as) CRight (CRight (Concat a1 a2)) -> case uncons a1 of Nothing -> Nothing Just (Tuple a as) -> Just (Tuple a (concat as a2))
  • 57. FIXING FREE DETOUR: FIXED LIST — COMPOSABLE TERMS (SCALA) def empty[A]: List[A] = Fixed[EmptyOrConsOrCat, A]( CLeft[Empty, ConsOrCat, List, A](Empty[List, A]())) def cons[A](a: A, as: List[A]): List[A] = Fixed[EmptyOrConsOrCat, A]( CRight[Empty, ConsOrCat, List, A]( CLeft[Cons, Concat, List, A](Cons[List, A](a, as)))) def concat[A](first: List[A], last: List[A]): List[A] = Fixed[EmptyOrConsOrCat, A]( CRight[Empty, ConsOrCat, List, A]( CRight[Cons, Concat, List, A](Concat[List, A](first, last)))) def uncons[A](as: List[A]): Option[(A, List[A])] = as.unfix match { case _ : CLeft[Empty, ConsOrCat, List, A] => None case v : CRight[Empty, ConsOrCat, List, A] => v.value match { case v : CLeft[Cons, Concat, List, A] => Some((v.value.head, v.value.tail)) case v : CRight[Cons, Concat, List, A] => uncons(v.value.first) match { case None => uncons(v.value.last) case Some((a, as)) => Some((a, concat(as, v.value.last))) } } }
  • 58. FIXING FREE BASIC TERM DEFINITION A program that halts, runs forever, or produces an A ^ | | t z e a T[Z[_], E[_], A] ^ ^ ^ | | | | | | Self | | Effect | Return Kind: (* -> *) -> (* -> *) -> * -> *
  • 59. FIXING FREE EXTENDED TERM DEFINITION A program that halts, errors with an E, runs forever, or produces an A ^ | | t e z e a T[E, Z[_], E[_], A] ^ ^ ^ ^ | | | | | | | | | Self | | | Effect | | Return Error Kind: * -> (* -> *) -> (* -> *) -> * -> *
  • 60. FIXING FREE PURITY data Pure e z f a = Pure a final case class Pure[E, Z[_], F[_], A](a: A)
  • 61. FIXING FREE EFFECTS data Effect e z f a = Effect (f a) final case class Effect[E, Z[_], F[_], A](fa: F[A])
  • 62. FIXING FREE SEQUENCE data Sequence e z f a = Sequence (forall x. (forall a0. z a0 -> (a0 -> z a) -> x) -> x) trait Sequence[E, Z[_], F[_], A] { type A0 def a: Z[A0] def f: A0 => Z[A] }
  • 63. FIXING FREE PARALLEL data Parallel e z f a = Parallel ( forall w. ( forall l r. z l -> z r -> (l -> r -> a) -> w) -> w) trait Parallel[E, Z[_], F[_], A] { type B type C def left: Z[B] def right: Z[C] def join: (B, C) => A }
  • 64. FIXING FREE FAILURE data Failure e z f a = Failure e data Recover e z f a = Recover (z a) (e -> z a) case class Failure[E, Z[_], F[_], A](error: E) case class Recover[E, Z[_], F[_], A](value: Z[A], f: E => Z[A])
  • 65. FIXING FREE ORDERED ALTERNATE data FirstSuccess e z f a = FirstSuccess (z a) (z a) case class FirstSuccess[E, Z[_], F[_], A](first: Z[A], second: Z[A])
  • 66. FIXING FREE TERM COMPOSITION data EitherF t1 t2 e z f a = LeftF (t1 e z f a) | RightF (t1 e z f a) sealed trait EitherF[T1[_, _[_], _[_], _], T2[_, _[_], _[_], _], E, Z[_], F[_], A] final case class LeftF[T1[_, _[_], _[_], _], T2[_, _[_], _[_], _], E, Z[_], F[_], A]( value: T1[E, Z, F, A]) extends EitherF[T1, T2, E, Z, F, A] final case class RightF[T1[_, _[_], _[_], _], T2[_, _[_], _[_], _], E, Z[_], F[_], A]( value: T2[E, Z, F, A]) extends EitherF[T1, T2, E, Z, F, A]
  • 67. FIXING FREE FIXING data Fixed t e f a = Fixed (t e (Fixed t e f) f a) final case class Fixed[T[_, _[_], _[_], _], E, F[_], A]( unfix: T[E, Fixed[T, E, F, ?], F, A] )
  • 68. FIXING FREE THE PROBLEMS WITH FIXING > Straining language capabilities > "Benign" boilerplate > But...type-level or macro machinery to the rescue?
  • 69. FIXING FREE WISH LIST > Language-level support for positively & negatively constrained, heterogeneous sets (unions) > Recursion as a computational feature > i.e. A NEW PROGRAMMING LANGUAGE
  • 70. CLOSING THOUGHTS WHERE WE ARE TODAY > "Post-free" is about reifying the structure of computation > By constraining the structure of subprograms, we liberate interpretation of them > We can do "post-free" now using a variety of techniques
  • 71. CLOSING THOUGHTS WHERE WE COULD GO TOMORROW > Post-free points to a world where programs are defined by: > (a) Defining computational features in terms of others > (b) Defining program effects in terms of others (onion architecture) > (c) Type-safe weaving, introspection, mocking, optimization, etc. > (d) Purely denotational semantics for programs
  • 72. THANK YOUFOLLOW ME ON TWITTER AT @JDEGOES READ MY BLOG ON HTTP://DEGOES.NET