Skip to content

Commit 6f3e7dd

Browse files
authored
Split examples and add Scalaz free example (#90)
1 parent 5575197 commit 6f3e7dd

File tree

4 files changed

+107
-4
lines changed

4 files changed

+107
-4
lines changed

build.sbt

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@ lazy val root = (project in file("."))
22
.settings(noPublishSettings)
33
.aggregate(coreJVM, coreJS)
44
.aggregate(testsJVM, testsJS)
5-
.aggregate(examplesJVM, examplesJS)
5+
.aggregate(examplesCatsJVM, examplesCatsJS)
6+
.aggregate(examplesScalazJVM, examplesScalazJS)
67
.aggregate(bench)
78
.aggregate(corezJVM, corezJS)
89
.aggregate(testszJVM, testszJS)
@@ -66,13 +67,25 @@ lazy val testsz = module("tests", hideFolder = true, prefixSuffix = "z")
6667
lazy val testszJVM = testsz.jvm
6768
lazy val testszJS = testsz.js
6869

69-
lazy val examples = module("examples")
70+
lazy val examplesCats = module("examples-cats")
7071
.dependsOn(core)
7172
.settings(noPublishSettings)
7273
.settings(macroSettings)
7374

74-
lazy val examplesJVM = examples.jvm
75-
lazy val examplesJS = examples.js
75+
lazy val examplesCatsJVM = examplesCats.jvm
76+
lazy val examplesCatsJS = examplesCats.js
77+
78+
lazy val examplesScalaz = module("examples-scalaz")
79+
.dependsOn(corez)
80+
.settings(noPublishSettings)
81+
.settings(macroSettings)
82+
.crossDepSettings(
83+
"org.scalaz" %% "scalaz-effect" % "7.2.15")
84+
85+
lazy val examplesScalazJVM = examplesScalaz.jvm
86+
lazy val examplesScalazJS = examplesScalaz.js
87+
88+
7689

7790
lazy val readme = jvmModule("readme")
7891
.dependsOn(coreJVM)
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
/*
2+
* Copyright 2016-2017 47 Degrees, LLC. <http://www.47deg.com>
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
import iotaz._
18+
19+
import scalaz._
20+
import scalaz.effect._
21+
import scalaz.syntax.apply._
22+
23+
import scala.Predef._
24+
25+
sealed trait TerminalOp[A]
26+
object TerminalOp {
27+
case object ReadLine extends TerminalOp[String]
28+
final case class WriteLine(msg: String) extends TerminalOp[Unit]
29+
}
30+
31+
sealed trait CounterOp[A]
32+
object CounterOp {
33+
final case object Reset extends CounterOp[Unit]
34+
final case object Increment extends CounterOp[Unit]
35+
final case object Decrement extends CounterOp[Unit]
36+
final case object Read extends CounterOp[Long]
37+
}
38+
39+
object FreeExample extends SafeApp {
40+
import TListK.::
41+
42+
type Algebra[A] = CopK[TerminalOp :: CounterOp :: TNilK, A]
43+
type FreeProgram[A] = Free[Algebra, A]
44+
type Program[A] = StateT[IO, Long, A]
45+
46+
val terminalToIO: TerminalOp ~> IO =
47+
λ[TerminalOp ~> IO] {
48+
case TerminalOp.ReadLine => IO.readLn
49+
case TerminalOp.WriteLine(msg) => IO.putStrLn(msg)
50+
}
51+
val counterToState: CounterOp ~> State[Long, ?] =
52+
λ[CounterOp ~> State[Long, ?]] {
53+
case CounterOp.Reset => State.put(0)
54+
case CounterOp.Increment => State.modify(_ + 1)
55+
case CounterOp.Decrement => State.modify(_ - 1)
56+
case CounterOp.Read => State.get
57+
}
58+
59+
val stateToProgram = λ[State[Long, ?] ~> Program](_.mapT(v => IO(v)))
60+
val ioToProgram = λ[IO ~> Program](io => StateT(s => io.map(s -> _)))
61+
val interpreter: Algebra ~> Program =
62+
CopK.NaturalTransformation.of[Algebra, Program](
63+
counterToState andThen stateToProgram,
64+
terminalToIO andThen ioToProgram)
65+
66+
implicit class AlgebraSyntax[F[_], A](fa: F[A])(
67+
implicit ev: CopK.Inject[F, Algebra]
68+
) {
69+
def liftFree: Free[Algebra, A] = Free.liftF(fa).mapSuspension(ev.inj)
70+
}
71+
72+
val terminate: FreeProgram[Unit] = Free.point(())
73+
lazy val freeProgram: FreeProgram[Unit] =
74+
for {
75+
value <- CounterOp.Read.liftFree
76+
_ <- TerminalOp.WriteLine(s"counter is $value").liftFree
77+
_ <- TerminalOp.WriteLine("command [+/-/0/exit]").liftFree
78+
input <- TerminalOp.ReadLine.liftFree
79+
_ <- input.trim.toLowerCase match {
80+
case "exit" => TerminalOp.WriteLine("See ya!").liftFree *> terminate
81+
case "+" => CounterOp.Increment.liftFree *> freeProgram
82+
case "-" => CounterOp.Decrement.liftFree *> freeProgram
83+
case "0" => CounterOp.Reset.liftFree *> freeProgram
84+
case _ => TerminalOp.WriteLine("Invalid command!").liftFree *> freeProgram
85+
}
86+
} yield ()
87+
88+
override val runc: IO[Unit] =
89+
freeProgram.foldMap(interpreter).run(0).map(_ => ())
90+
}

0 commit comments

Comments
 (0)