-
Notifications
You must be signed in to change notification settings - Fork 9
/
ComposeFreeMonads.scala
73 lines (61 loc) · 2.12 KB
/
ComposeFreeMonads.scala
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
package examples.cats
import cats.data._
import cats.free._
import cats._
import freasymonad.cats.free
import scala.collection.mutable.ListBuffer
import scala.io.StdIn
// example based off https://github.com/typelevel/cats/blob/master/docs/src/main/tut/datatypes/freemonad.md#composing-free-monads-adts
object ComposeFreeMonads extends App {
@free trait Interact {
type InteractF[A] = Free[Adt, A]
sealed trait Adt[A]
def ask(prompt: String): InteractF[String]
def tell(msg: String): InteractF[Unit]
}
@free trait DataSource {
type DataSourceF[A] = Free[Adt, A]
sealed trait Adt[A]
def addCat(a: String): DataSourceF[Unit]
def getAllCats: DataSourceF[List[String]]
def addAndGetAllCats(a: String): DataSourceF[List[String]] =
for {
_ <- addCat(a)
c <- getAllCats
} yield c
}
type CatsApp[A] = EitherK[DataSource.Adt, Interact.Adt, A]
// program1 and program2 are the same.
// This library lets you choose which style you like.
def program1(implicit I: Interact.Injects[CatsApp], D : DataSource.Injects[CatsApp]): Free[CatsApp, Unit] = {
import I._, D._
for {
cat <- ask("What's the kitty's name?")
cats <- addAndGetAllCats(cat)
_ <- tell(cats.toString)
} yield ()
}
val program2: Free[CatsApp, Unit] = {
import Interact.injectOps._, DataSource.injectOps._
for {
cat <- ask[CatsApp]("What's the kitty's name?")
cats <- addAndGetAllCats[CatsApp](cat)
_ <- tell[CatsApp](cats.toString)
} yield ()
}
val consoleCats: Interact.Interp[Id] = new Interact.Interp[Id] {
def ask(prompt: String): Id[String] = {
println(prompt)
StdIn.readLine()
}
def tell(msg: String): Id[Unit] = println(msg)
}
val inMemoryDatasource: DataSource.Interp[Id] = new DataSource.Interp[Id] {
private[this] val memDataSet = new ListBuffer[String]
def addCat(a: String): Id[Unit] = memDataSet.append(a)
def getAllCats: Id[List[String]] = memDataSet.toList
}
val interpreter: CatsApp ~> Id = inMemoryDatasource or consoleCats
program1.foldMap(interpreter)
program2.foldMap(interpreter)
}