Skip to content

Commit eafb45d

Browse files
committed
Update FreeMonad.md
1 parent a6d3725 commit eafb45d

File tree

1 file changed

+91
-0
lines changed

1 file changed

+91
-0
lines changed

FreeMonad.md

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,3 +61,94 @@ def runKVS[A](kvs: Free[KVS, A], table: Map[String, String]): Map[String, String
6161

6262
runKVS(modify("a", f => f.toUpperCase), Map("a"->"aa", "b" -> "bb"))
6363
```
64+
###Free Monads and Scalaz###
65+
```
66+
package io.underscore.freemonadsaresimple
67+
68+
69+
import scalaz.{Free, Functor}
70+
71+
object Mock {
72+
case class Result(value: String, next: Boolean)
73+
case class Repository(next: Boolean) {
74+
def execute(sql: String): Result = Result(sql.toUpperCase, next)
75+
}
76+
}
77+
78+
import io.underscore.freemonadsaresimple.Mock._
79+
80+
object Language {
81+
82+
sealed trait Data[+A]
83+
84+
case class Template[Next](template: String, call: String => Next) extends Data[Next]
85+
86+
case class Call[Next](template: String, call: Repository => Next) extends Data[Next]
87+
88+
case class Convert[Next](convert: Result, call: Result => Next) extends Data[Next]
89+
90+
case class Fail(msg: String) extends Data[Nothing]
91+
92+
implicit val functor = new Functor[Data] {
93+
override def map[A, B](data: Data[A])(map: (A) => B): Data[B] = data match {
94+
case Template(template, call) => Template(template, v => map(call(v)))
95+
case Call(template, call) => Call(template, connection => map(call(connection)))
96+
case Convert(from, convert) => Convert(from, entity => map(convert(entity)))
97+
case Fail(msg) => Fail(msg)
98+
}
99+
}
100+
}
101+
102+
object Logic {
103+
104+
import Language._
105+
106+
val templates: Map[String, String] = Map("a" -> "table_a")
107+
108+
def template(template: String): Free[Data, String] = Free.liftF(Template(template, t => t))
109+
110+
def call(sql: String): Free[Data, Result] = Free.liftF(Call(sql, connection =>
111+
connection.execute(sql)
112+
))
113+
114+
def convert(rs: Result): Free[Data, String] = Free.liftF(Convert(rs, r => r.value))
115+
}
116+
117+
object Interpreter {
118+
119+
import Language._
120+
121+
val templates: Map[String, String] = Map(
122+
"a" -> "table_a"
123+
)
124+
125+
def run[A](repository: Repository, data: Free[Data, A]): Either[String, A] = data.resume.fold({
126+
case Template(template, call) =>
127+
templates.get(template) match {
128+
case Some(t) => run(repository, call(t))
129+
case None => run(repository, Free.liftF(Fail(template)))
130+
}
131+
case Call(template, call) => run(repository, call(repository))
132+
case Convert(result, convert) =>
133+
if (result.next) run(repository, convert(result)) else run(repository, Free.liftF(Fail("No value")))
134+
case Fail(msg) => Left(msg)
135+
},
136+
(a: A) => Right(a)
137+
)
138+
}
139+
140+
object FM extends App {
141+
142+
import Interpreter._
143+
import Logic._
144+
145+
def request(name: String) = for {
146+
sql <- template(name)
147+
result <- call(sql)
148+
response <- convert(result)
149+
} yield response
150+
151+
val o = run(Repository(true), request("a"))
152+
println(o)
153+
}
154+
```

0 commit comments

Comments
 (0)