Skip to content
This repository was archived by the owner on Jun 10, 2021. It is now read-only.

Commit dbe2aac

Browse files
committed
FState, monadic operations on FState
1 parent 58526b9 commit dbe2aac

File tree

4 files changed

+125
-0
lines changed

4 files changed

+125
-0
lines changed
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package asyncstreams
2+
3+
import scala.concurrent.{ExecutionContext, Future}
4+
5+
class FState[S, A](func: S => Future[(A, S)]) extends ((S) => Future[(A, S)]) {
6+
def apply(s: S) = func(s)
7+
8+
def flatMap[B](f: A => FState[S, B])(implicit ex: ExecutionContext): FState[S, B] = FState[S, B](
9+
(s: S) => func(s) flatMap ((fst: A, snd: S) => f(fst)(snd)).tupled
10+
)
11+
12+
def map[B](f: A => B)(implicit ex: ExecutionContext): FState[S, B] =
13+
flatMap((a: A) => FState.unit(f(a)))
14+
}
15+
16+
object FState {
17+
def apply[S, A](f: S => Future[(A, S)]) = new FState[S, A](f)
18+
def unit[S, A](a: => A)(implicit ex: ExecutionContext) = FState[S, A]((s: S) => Future((a, s)))
19+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
package asyncstreams
2+
3+
import scala.concurrent.{ExecutionContext, Future}
4+
import scalaz.MonadPlus
5+
6+
class FStateMonad[S](implicit ex: ExecutionContext)
7+
extends MonadPlus[({ type f[X] = FState[S, X]})#f] with FStateMonadFunctions {
8+
type F[X] = FState[S, X]
9+
10+
override def empty[A]: F[A] = FState((s: S) => ENDF)
11+
12+
override def point[A](a: => A): F[A] = FState.unit(a)
13+
14+
override def bind[A, B](m: F[A])(f: A => F[B]): F[B] =
15+
FState((s: S) => m(s) flatMap {
16+
case null => ENDF
17+
case (fst, snd) => f(fst)(snd)
18+
})
19+
20+
override def plus[A](a: F[A],b: => F[A]): F[A] = bind(a)(_ => b)
21+
22+
def conds(f: S => Boolean): F[Boolean] = bind(gets[S])(vs => point(f(vs)))
23+
def fconds(f: S => F[Boolean]): F[Boolean] = bind(gets[S])(f)
24+
def mods(f: S => S): F[S] = bind(gets[S])(vs => puts(f(vs)))
25+
26+
def forM_[A](cond: S => Boolean, mod: S => S)(action: => F[A]): F[Unit] =
27+
whileM_(conds(cond), bind(action)(va => mods(mod)))
28+
}
29+
30+
trait FStateMonadFunctions {
31+
def gets[S](implicit ex: ExecutionContext): FState[S, S] = FState((s: S) => Future((s, s)))
32+
def puts[S](news: S)(implicit ex: ExecutionContext): FState[S, S] = FState((_: S) => Future((news, news)))
33+
34+
def conds[S](f: S => Boolean)(implicit m: FStateMonad[S]): FState[S, Boolean] =
35+
m.conds(f)
36+
37+
def fconds[S](f: S => FState[S, Boolean])(implicit m: FStateMonad[S]): FState[S, Boolean] =
38+
m.fconds(f)
39+
40+
def mods[S : FStateMonad](f: S => S)(implicit m: FStateMonad[S]): FState[S, S] =
41+
m.mods(f)
42+
}

src/main/scala/asyncstreams/package.scala

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,8 @@ package object asyncstreams {
77

88
implicit def asyncStreamInstance(implicit executor: ExecutionContext): Monad[AsyncStream] =
99
new AsyncStreamMonad
10+
11+
def fStateInstance[S](implicit executor: ExecutionContext) = new FStateMonad[S]
12+
13+
object monadops extends FStateMonadFunctions
1014
}
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
package asyncstreams
2+
3+
import monadops._
4+
5+
import scala.concurrent.{Await, Future}
6+
import scala.concurrent.duration._
7+
import scala.concurrent.ExecutionContext.Implicits.global
8+
9+
class FStateTests extends BaseSuite {
10+
private def wait[T](f: Future[T]): T = Await.result(f, 10.seconds)
11+
12+
test("FState in for-comprehensions") {
13+
val fsm = fStateInstance[Int]
14+
15+
val t = for {
16+
a <- fsm.point(10)
17+
b = a + 1
18+
} yield b
19+
20+
wait(t(0)) shouldBe (11, 0)
21+
}
22+
23+
test("gets & puts") {
24+
val fsm = fStateInstance[Int]
25+
26+
val t = for {
27+
_ <- fsm.whileM_(gets[Int] map (_ < 10), for {
28+
i <- gets[Int]
29+
_ <- puts(i + 1)
30+
} yield (()))
31+
v1 <- gets[Int]
32+
} yield v1
33+
34+
wait(t(0)) shouldBe (10, 10)
35+
}
36+
37+
test("conds & mods") {
38+
implicit val fsm = fStateInstance[Int]
39+
40+
val t = for {
41+
_ <- fsm.whileM_(conds(_ < 10), mods(_ + 1))
42+
v1 <- gets[Int]
43+
} yield v1
44+
45+
wait(t(0)) shouldBe (10, 10)
46+
}
47+
48+
test("forM_") {
49+
val fsm = fStateInstance[Int]
50+
51+
val t = for {
52+
_ <- fsm.forM_(_ < 10, _ + 1) {
53+
fsm.point("AAAAAA")
54+
}
55+
v1 <- gets[Int]
56+
} yield v1
57+
58+
wait(t(0)) shouldBe (10, 10)
59+
}
60+
}

0 commit comments

Comments
 (0)