@@ -61,3 +61,94 @@ def runKVS[A](kvs: Free[KVS, A], table: Map[String, String]): Map[String, String
6161
6262runKVS(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