Skip to content
Browse files

Renamed Coroutine to Free. Added a practical implementation of DList.

  • Loading branch information...
1 parent fe32fb5 commit 0c299ee4c15049310f2a5b229f46f5d5621d6702 @runarorama runarorama committed Nov 17, 2011
View
69 core/src/main/scala/scalaz/DList.scala
@@ -0,0 +1,69 @@
+package scalaz
+
+import Free._
+import std.function._
+
+trait DList[A] {
+ import DList._
+ def apply(xs: List[A]): Trampoline[List[A]]
+ def toList: List[A] = apply(List()).run
+ def +:(a: A): DList[A] = mkDList(as => suspend(apply(as) map (a :: _)))
+ def :+(a: A): DList[A] = mkDList(as => suspend(apply(a :: as)))
+ def ++(as: => DList[A]): DList[A] =
+ mkDList(xs => as(xs) >>= (ys => apply(ys)))
+ def uncons[B](z: => B, f: (A, DList[A]) => B): B =
+ (apply(List()) >>= {
+ case List() => return_(z)
+ case x :: xs => return_(f(x, fromList(xs)))
+ }).run
+ def head: A = uncons(sys.error("DList.head: empty list"), (x, y) => x)
+ def tail: DList[A] = uncons(sys.error("DList.tail: empty list"), (x, y) => y)
+ def foldr[B](z: => B)(f: (A, => B) => B): B = {
+ def go(xs: DList[A], z: => B, f: (A, => B) => B): Trampoline[B] =
+ suspend(xs.uncons(return_(z), (h, t) => go(t, z, f) map (x => f(h, x))))
+ go(this, z, f).run
+ }
+ def map[B](f: A => B): DList[B] =
+ foldr(DList[B]())((x, y) => f(x) +: y)
+ def flatMap[B](f: A => DList[B]) =
+ foldr(DList[B]())((x, y) => f(x) ++ y)
+}
+
+object DList extends DListFunctions with DListInstances {
+ def apply[A](xs: A*) = fromList(xs.toList)
+}
+
+trait DListInstances {
+ implicit def dlistMonoid[A]: Monoid[DList[A]] = new Monoid[DList[A]] {
+ val zero = DList[A]()
+ def append(a: DList[A], b: => DList[A]) = a ++ b
+ }
+ implicit val dlistMonad: Monad[DList] = new MonadPlus[DList] {
+ def point[A](a: => A) = DList(a)
+ def bind[A, B](as: DList[A])(f: A => DList[B]) = as flatMap f
+ def plus[A](a: DList[A], b: => DList[A]) = a ++ b
+ def empty[A] = DList()
+ }
+}
+
+trait DListFunctions {
+ def mkDList[A](f: (=> List[A]) => Trampoline[List[A]]): DList[A] =
+ new DList[A] {
+ def apply(xs: List[A]) = f(xs)
+ }
+ def DL[A](f: (=> List[A]) => List[A]): DList[A] = mkDList(xs => return_(f(xs)))
+ def fromList[A](as: => List[A]): DList[A] =
+ DL(bs => as ++ bs)
+ def concat[A](xs: List[DList[A]]): DList[A] =
+ xs.foldRight(DList[A]())(_ ++ _)
+ def replicate[A](n: Int, a: A): DList[A] =
+ DL(xs => {
+ def go(m: Int): List[A] = if (m <= 0) xs else a :: go(m - 1)
+ go(n)
+ })
+ def unfoldr[A, B](b: B, f: B => Option[(A, B)]): DList[A] = {
+ def go(b: B, f: B => Option[(A, B)]): Trampoline[DList[A]] =
+ f(b) map { case (a, c) => suspend(go(c, f)) map (a +: _) } getOrElse return_(DList())
+ go(b, f).run
+ }
+}
View
33 core/src/main/scala/scalaz/Coroutine.scala → core/src/main/scala/scalaz/Free.scala
@@ -19,7 +19,7 @@ object Free extends FreeFunctions with FreeInstances {
case class Gosub[S[_], A, B](a: Free[S, A],
f: A => Free[S, B]) extends Free[S, B]
- /** A computation that can be stepped through, suspended, paused */
+ /** A computation that can be stepped through, suspended, and paused */
type Trampoline[A] = Free[Function0, A]
/** A computation that produces values of type `A`, eventually resulting in a value of type `B`. */
@@ -37,15 +37,15 @@ sealed trait Free[S[_], A] {
final def map[B](f: A => B): Free[S, B] =
flatMap(a => Return(f(a)))
- /** Binds the given continuation to the result of this computation. This implementation is codense,
- * so all binds are reassociated to the right. */
+ /** Binds the given continuation to the result of this computation.
+ * All left-associated binds are reassociated to the right. */
final def >>=[B](f: A => Free[S, B]): Free[S, B] = this match {
case Gosub(a, g) => Gosub(a, (x: Any) => Gosub(g(x), f))
case a => Gosub(a, f)
}
- /** Binds the given continuation to the result of this computation. This implementation is codense,
- * so all binds are reassociated to the right. */
+ /** Binds the given continuation to the result of this computation.
+ * All left-associated binds are reassociated to the right. */
final def flatMap[B](f: A => Free[S, B]): Free[S, B] =
this >>= f
@@ -134,13 +134,11 @@ sealed trait Free[S[_], A] {
}
}
-case class Request[I, O, A](request: I, response: O => A)
-
object Trampoline extends TrampolineInstances
trait TrampolineInstances {
implicit val trampolineMonad: Monad[Trampoline] = new Monad[Trampoline] {
- override def point[A](a: => A) = suspend(a)
+ override def point[A](a: => A) = return_(a)
def bind[A, B](ta: Trampoline[A])(f: A => Trampoline[B]) = ta flatMap f
}
}
@@ -178,15 +176,18 @@ trait FreeInstances {
trait FreeFunctions {
/** Collapse a trampoline to a single step. */
- def reset[A](r: Trampoline[A]): Trampoline[A] = suspend(r.run)
+ def reset[A](r: Trampoline[A]): Trampoline[A] = return_(r.run)
+
+ /** Suspend the given computation in a single step. */
+ def return_[S[_], A](value: => A)(implicit p: Pointed[S]): Free[S, A] =
+ Suspend[S, A](p.point(Return[S, A](value)))
- /** Suspend the given computation in a trampoline step. */
- def suspend[A](value: => A): Trampoline[A] =
- Suspend[Function0, A](() => Return[Function0, A](value))
+ def suspend[S[_], A](value: => Free[S, A])(implicit p: Pointed[S]): Free[S, A] =
+ Suspend[S, A](p.point(value))
/** A trampoline step that doesn't do anything. */
def pause: Trampoline[Unit] =
- suspend(())
+ return_(())
/** A source that produces the given value. */
def produce[A](a: A): Source[A, Unit] =
@@ -195,11 +196,5 @@ trait FreeFunctions {
/** A sink that waits for a single value and returns it. */
def await[A]: Sink[A, A] =
Suspend[({type f[x] = (=> A) => x})#f, A](a => Return[({type f[x] = (=> A) => x})#f, A](a))
-
- /** A request that simply returns the response. */
- def request[I, O](x: I): Free[({type f[x] = Request[I, O, x]})#f, O] =
- Suspend[({type f[x] = Request[I, O, x]})#f, O](Request(x, Return[({type f[x] = Request[I, O, x]})#f, O](_: O)))
}
-
-
View
10 effect/src/main/scala/scalaz/effect/IO.scala
@@ -136,7 +136,7 @@ sealed trait IO[A] {
object IO extends IOFunctions with IOInstances {
def apply[A](a: => A): IO[A] =
- io(rw => suspend(rw -> a))
+ io(rw => return_(rw -> a))
}
trait IOInstances0 {
@@ -173,19 +173,19 @@ trait IOStd {
def getChar: IO[Char] = IO(readChar())
/** Writes a character to standard output. */
- def putChar(c: Char): IO[Unit] = io(rw => suspend(rw -> {
+ def putChar(c: Char): IO[Unit] = io(rw => return_(rw -> {
print(c);
()
}))
/** Writes a string to standard output. */
- def putStr(s: String): IO[Unit] = io(rw => suspend(rw -> {
+ def putStr(s: String): IO[Unit] = io(rw => return_(rw -> {
print(s);
()
}))
/** Writes a string to standard output, followed by a newline.*/
- def putStrLn(s: String): IO[Unit] = io(rw => suspend(rw -> {
+ def putStrLn(s: String): IO[Unit] = io(rw => return_(rw -> {
println(s);
()
}))
@@ -194,7 +194,7 @@ trait IOStd {
def readLn: IO[String] = IO(readLine())
/** Write the given value to standard output. */
- def putOut[A](a: A): IO[Unit] = io(rw => suspend(rw -> {
+ def putOut[A](a: A): IO[Unit] = io(rw => return_(rw -> {
print(a);
()
}))
View
5 effect/src/main/scala/scalaz/effect/ST.scala
@@ -5,6 +5,7 @@ import RealWorld._
import STRef._
import STArray._
import ST._
+import std.function._
/**Mutable variable in state thread S containing a value of type A. http://research.microsoft.com/en-us/um/people/simonpj/papers/lazy-functional-state-threads.ps.Z */
sealed trait STRef[S, A] {
@@ -142,7 +143,7 @@ trait STFunctions {
// Implicit conversions between IO and ST
implicit def STToIO[A](st: ST[RealWorld, A]): IO[A] =
- IO.io(rw => Coroutine.suspend(st(rw)))
+ IO.io(rw => Free.return_(st(rw)))
/**Put a value in a state thread */
def returnST[S, A](a: => A): ST[S, A] =
@@ -192,4 +193,4 @@ trait STInstances {
def point[A](a: => A): ST[S, A] = returnST(a)
def bind[A, B](fa: ST[S, A])(f: (A) => ST[S, B]): ST[S, B] = fa flatMap f
}
-}
+}

0 comments on commit 0c299ee

Please sign in to comment.
Something went wrong with that request. Please try again.