Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

more checkpoint

  • Loading branch information...
commit 98d48afa1785fb94ed5073f9a3df76c7f45319cc 1 parent 89cc2bc
@jaked authored
View
16 _code/scala-logic/Bridge.scala
@@ -1,4 +1,4 @@
-class Bridge(Logic: Logic) {
+class Bridge(val Logic: Logic) {
import Logic._
object Person extends Enumeration {
@@ -14,11 +14,11 @@ class Bridge(Logic: Logic) {
lightOnLeft: Boolean,
timeRemaining: Int)
- private def chooseTwo(list: List[Person]): T[(Person,Person)] =
+ def chooseTwo(list: List[Person]): T[(Person,Person)] =
for { p1 <- or(list); p2 <- or(list); if p1 < p2 }
yield (p1, p2)
- private def next(state: State): T[State] = {
+ def next(state: State): T[State] = {
if (state.lightOnLeft) {
for {
(p1, p2) <- chooseTwo(state.left)
@@ -40,18 +40,16 @@ class Bridge(Logic: Logic) {
}
}
- private def tree(path: List[State]): T[List[State]] =
+ def tree(path: List[State]): T[List[State]] =
unit(path) |
(for {
state <- next(path.head)
path <- tree(state :: path)
} yield path)
- def search(n: Int): List[List[State]] = {
+ def search: T[List[State]] = {
val start = List(State(Person.all, true, 60))
- val t =
- for { path <- tree(start); if path.head.left == Nil }
- yield path
- run(t, n)
+ for { path <- tree(start); if path.head.left == Nil }
+ yield path
}
}
View
177 _code/scala-logic/Logic.scala
@@ -16,7 +16,7 @@ trait Logic { L =>
def runAcc(t: T[A], n: Int, acc: List[A]): List[A] =
if (n <= 0) acc.reverse else
split(t) match {
- case None => Nil
+ case None => acc
case Some((a, t)) => runAcc(t, n - 1, a :: acc)
}
runAcc(t, n, Nil)
@@ -33,178 +33,3 @@ trait Logic { L =>
implicit def syntax[A](t: T[A]) = Syntax(t)
}
-
-object LogicList extends Logic {
- type T[A] = List[A]
-
- def fail[A] = Nil
- def unit[A](a: A) = a :: Nil
- def or[A](t1: List[A], t2: => List[A]) = t1 ::: t2
- def apply[A,B](t: List[A], f: A => B) = t.map(f)
- def bind[A,B](t: List[A], f: A => List[B]) = t.flatMap(f)
- def filter[A](t: List[A], p: A => Boolean) = t.filter(p)
- def split[A](t: List[A]) =
- t match {
- case Nil => None
- case h :: t => Some(h, t)
- }
-}
-
-object LogicSFK extends Logic {
- type FK[R] = () => R
- type SK[A,R] = (A, FK[R]) => R
-
- trait T[A] { def apply[R](sk: SK[A,R], fk: FK[R]): R }
-
- def fail[A] =
- new T[A] {
- def apply[R](sk: SK[A,R], fk: FK[R]) = fk()
- }
-
- def unit[A](a: A) =
- new T[A] {
- def apply[R](sk: SK[A,R], fk: FK[R]) = sk(a, fk)
- }
-
- def or[A](t1: T[A], t2: => T[A]) =
- new T[A] {
- def apply[R](sk: SK[A,R], fk: FK[R]) = t1(sk, { () => t2(sk, fk) })
- }
-
- def bind[A,B](t: T[A], f: A => T[B]) =
- new T[B] {
- def apply[R](sk: SK[B,R], fk: FK[R]) =
- t(({ (a, fk) => f(a)(sk, fk) }: SK[A,R]), fk)
- }
-
- def apply[A,B](t: T[A], f: A => B) =
- new T[B] {
- def apply[R](sk: SK[B,R], fk: FK[R]) =
- t(({ (a, fk) => sk(f(a), fk) }: SK[A,R]), fk)
- }
-
- def filter[A](t: T[A], p: A => Boolean) =
- new T[A] {
- def apply[R](sk: SK[A,R], fk: FK[R]) =
- t(({ (a, fk) => if (p(a)) sk(a, fk) else fk() }: SK[A,R]), fk)
- }
-
- def split[A](t: T[A]) = {
- def unsplit(fk: FK[Option[(A,T[A])]]): T[A] =
- fk() match {
- case None => fail
- case Some((a, t)) => or(unit(a), t)
- }
- def sk : SK[A,Option[(A,T[A])]] =
- { (a, fk) => Some((a, bind(unit(fk), unsplit))) }
- t(sk, { () => None })
- }
-}
-
-object LogicSKE extends Logic {
- case object Fail extends Exception
-
- type T[A] = (A => Unit) => Unit
-
- def fail[A] = { sk => throw Fail }
-
- def unit[A](a: A) = { sk => sk(a) }
-
- def or[A](t1: T[A], t2: => T[A]) =
- { sk =>
- try { t1(sk) }
- catch { case Fail => t2(sk) }
- }
-
- def bind[A,B](t: T[A], f: A => T[B]) =
- { sk => t(a => f(a)(sk)) }
-
- def apply[A,B](t: T[A], f: A => B) =
- { sk => t(a => sk(f(a))) }
-
- def filter[A](t: T[A], p: A => Boolean) =
- { sk =>
- t(a => if (p(a)) sk(a) else throw Fail)
- }
-
- case object Finish extends Exception
-
- def split[A](t: T[A]) = throw new Exception("unimplemented")
-
- override def run[A](t: T[A], n: Int): List[A] = {
- if (n <= 0) return Nil
- val lb = new scala.collection.mutable.ListBuffer[A]
- def sk(a: A) = {
- lb += a
- throw (if (lb.size < n) Fail else Finish)
- }
- try {
- t(sk)
- throw new Exception("not reached")
- }
- catch { case Fail | Finish => lb.result }
- }
-}
-
-object LogicSKE2 extends Logic {
- case object Fail extends Exception
- class Succeed[A](val a: A, var s: List[() => Unit]) extends Exception
-
- type T[A] = (A => Unit) => Unit
-
- def fail[A] = { sk => throw Fail }
-
- def unit[A](a: A) = { sk => sk(a) }
-
- def or[A](t1: T[A], t2: => T[A]) =
- { sk =>
- try { t1(sk) }
- catch {
- case Fail => t2(sk)
- case e: Succeed[_] => {
- e.s = { () => t2(sk) } :: e.s
- throw e
- }
- }
- }
-
- def bind[A,B](t: T[A], f: A => T[B]) =
- { sk => t(a => f(a)(sk)) }
-
- def apply[A,B](t: T[A], f: A => B) =
- { sk => t(a => sk(f(a))) }
-
- def filter[A](t: T[A], p: A => Boolean) =
- { sk =>
- t(a => if (p(a)) sk(a) else throw Fail)
- }
-
- def split[A](t: T[A]) = {
- def restore(s: List[() => Unit]) {
- s match {
- case Nil => throw Fail
- case cp :: s =>
- try { restore(s) }
- catch {
- case Fail => cp()
- case e: Succeed[_] => {
- e.s = cp :: e.s
- throw e
- }
- }
- }
- }
- def unsplit[A](s: List[() => Unit]): T[A] =
- try { restore(s); throw new Exception("not reached") }
- catch {
- case Fail => fail
- case e: Succeed[A] => or(unit(e.a), bind(unit(e.s), unsplit))
- }
-
- try { t(a => throw new Succeed(a, Nil)); throw new Exception("not reached") }
- catch {
- case Fail => None
- case e: Succeed[A] => Some((e.a, bind(unit(e.s), unsplit)))
- }
- }
-}
View
15 _code/scala-logic/LogicList.scala
@@ -0,0 +1,15 @@
+object LogicList extends Logic {
+ type T[A] = List[A]
+
+ def fail[A] = Nil
+ def unit[A](a: A) = a :: Nil
+ def or[A](t1: List[A], t2: => List[A]) = t1 ::: t2
+ def apply[A,B](t: List[A], f: A => B) = t.map(f)
+ def bind[A,B](t: List[A], f: A => List[B]) = t.flatMap(f)
+ def filter[A](t: List[A], p: A => Boolean) = t.filter(p)
+ def split[A](t: List[A]) =
+ t match {
+ case Nil => None
+ case h :: t => Some(h, t)
+ }
+}
View
50 _code/scala-logic/LogicSFK.scala
@@ -0,0 +1,50 @@
+object LogicSFK extends Logic {
+ type FK[R] = () => R
+ type SK[A,R] = (A, FK[R]) => R
+
+ trait T[A] { def apply[R](sk: SK[A,R], fk: FK[R]): R }
+
+ def fail[A] =
+ new T[A] {
+ def apply[R](sk: SK[A,R], fk: FK[R]) = fk()
+ }
+
+ def unit[A](a: A) =
+ new T[A] {
+ def apply[R](sk: SK[A,R], fk: FK[R]) = sk(a, fk)
+ }
+
+ def or[A](t1: T[A], t2: => T[A]) =
+ new T[A] {
+ def apply[R](sk: SK[A,R], fk: FK[R]) = t1(sk, { () => t2(sk, fk) })
+ }
+
+ def bind[A,B](t: T[A], f: A => T[B]) =
+ new T[B] {
+ def apply[R](sk: SK[B,R], fk: FK[R]) =
+ t(({ (a, fk) => f(a)(sk, fk) }: SK[A,R]), fk)
+ }
+
+ def apply[A,B](t: T[A], f: A => B) =
+ new T[B] {
+ def apply[R](sk: SK[B,R], fk: FK[R]) =
+ t(({ (a, fk) => sk(f(a), fk) }: SK[A,R]), fk)
+ }
+
+ def filter[A](t: T[A], p: A => Boolean) =
+ new T[A] {
+ def apply[R](sk: SK[A,R], fk: FK[R]) =
+ t(({ (a, fk) => if (p(a)) sk(a, fk) else fk() }: SK[A,R]), fk)
+ }
+
+ def split[A](t: T[A]) = {
+ def unsplit(fk: FK[Option[(A,T[A])]]): T[A] =
+ fk() match {
+ case None => fail
+ case Some((a, t)) => or(unit(a), t)
+ }
+ def sk : SK[A,Option[(A,T[A])]] =
+ { (a, fk) => Some((a, bind(unit(fk), unsplit))) }
+ t(sk, { () => None })
+ }
+}
View
63 _code/scala-logic/LogicSFKDefunc.scala
@@ -0,0 +1,63 @@
+object LogicSFKDefunc extends Logic {
+ sealed trait T[A]
+ case class Fail[A]() extends T[A]
+ case class Unit[A](a: A) extends T[A]
+ case class Or[A](t1: T[A], t2: () => T[A]) extends T[A]
+ case class Bind[A,B](t: T[A], f: A => T[B]) extends T[B]
+ case class Apply[A,B](t: T[A], f: A => B) extends T[B]
+ case class Filter[A](t: T[A], p: A => Boolean) extends T[A]
+
+ sealed trait FK[R]
+ case class FKOr[A,R](t: () => T[A], sk: SK[A,R], fk: FK[R]) extends FK[R]
+ case class FKSplit[R](r: R) extends FK[R]
+
+ sealed trait SK[A,R]
+ case class SKBind[A,B,R](f: A => T[B], sk: SK[B,R]) extends SK[A,R]
+ case class SKApply[A,B,R](f: A => B, sk: SK[B,R]) extends SK[A,R]
+ case class SKFilter[A,R](p: A => Boolean, sk: SK[A,R]) extends SK[A,R]
+ case class SKSplit[A,R](r: (A, FK[R]) => R) extends SK[A,R]
+
+ def fail[A] = Fail()
+ def unit[A](a: A) = Unit(a)
+ def or[A](t1: T[A], t2: => T[A]) = Or(t1, { () => t2 })
+ def bind[A,B](t: T[A], f: A => T[B]) = Bind(t, f)
+ def apply[A,B](t: T[A], f: A => B) = Apply(t, f)
+ def filter[A](t: T[A], p: A => Boolean) = Filter(t, p)
+
+ def split[A](t: T[A]) = {
+ def unsplit[A](fk: FK[Option[(A, T[A])]]): T[A] =
+ applyFK(fk) match {
+ case None => fail
+ case Some((a, t)) => or(unit(a), t)
+ }
+
+ def applyT[A,R](t: T[A], sk: SK[A,R], fk: FK[R]): R =
+ t match {
+ case Fail() => applyFK(fk)
+ case Unit(a) => applySK(sk, a, fk)
+ case Or(t1, t2) => applyT(t1, sk, FKOr(t2, sk, fk))
+ case Bind(t, f) => applyT(t, SKBind(f, sk), fk)
+ case Apply(t, f) => applyT(t, SKApply(f, sk), fk)
+ case Filter(t, p) => applyT(t, SKFilter(p, sk), fk)
+ }
+
+ def applyFK[R](fk: FK[R]): R =
+ fk match {
+ case FKOr(t, sk, fk) => applyT(t(), sk, fk)
+ case FKSplit(r) => r
+ }
+
+ def applySK[A,R](sk: SK[A,R], a: A, fk: FK[R]): R =
+ sk match {
+ case SKBind(f, sk) => applyT(f(a), sk, fk)
+ case SKApply(f, sk) => applySK(sk, f(a), fk)
+ case SKFilter(p, sk) => if (p(a)) applySK(sk, a, fk) else applyFK(fk)
+ case SKSplit(r) => r(a, fk)
+ }
+
+ applyT[A,Option[(A,T[A])]](
+ t,
+ SKSplit((a, fk) => Some((a, bind(unit(fk), unsplit)))),
+ FKSplit(None))
+ }
+}
View
83 _code/scala-logic/LogicSFKDefuncTailrec.scala
@@ -0,0 +1,83 @@
+object LogicSFKDefuncTailrec extends Logic {
+ sealed trait T[A]
+ case class Fail[A]() extends T[A]
+ case class Unit[A](a: A) extends T[A]
+ case class Or[A](t1: T[A], t2: () => T[A]) extends T[A]
+ case class Bind[A,B](t: T[A], f: A => T[B]) extends T[B]
+ case class Apply[A,B](t: T[A], f: A => B) extends T[B]
+ case class Filter[A](t: T[A], p: A => Boolean) extends T[A]
+ case class Unsplit[A](fk: FK) extends T[A]
+
+ type R = Option[(Any,T[Any])]
+
+ sealed trait FK
+ case class FKOr(t: () => T[Any], sk: SK, fk: FK) extends FK
+ case class FKSplit(r: R) extends FK
+
+ sealed trait SK
+ case class SKBind(f: Any => T[Any], sk: SK) extends SK
+ case class SKApply(f: Any => Any, sk: SK) extends SK
+ case class SKFilter(p: Any => Boolean, sk: SK) extends SK
+ case class SKSplit(r: (Any, FK) => R) extends SK
+
+ sealed trait K
+ case object KReturn extends K
+ case class KUnsplit(sk: SK, fk: FK, k: K) extends K
+
+ def fail[A] = Fail()
+ def unit[A](a: A) = Unit(a)
+ def or[A](t1: T[A], t2: => T[A]) = Or(t1, { () => t2 })
+ def bind[A,B](t: T[A], f: A => T[B]) = Bind(t, f)
+ def apply[A,B](t: T[A], f: A => B) = Apply(t, f)
+ def filter[A](t: T[A], p: A => Boolean) = Filter(t, p)
+
+ def split[A](t2: T[A]): Option[(A,T[A])] = {
+ var app = 1
+ var t = t2.asInstanceOf[T[Any]]
+ var a: Any = null
+ var r: R = null
+ var sk: SK = SKSplit((a, fk) => Some((a, Unsplit(fk))))
+ var fk: FK = FKSplit(None)
+ var k: K = KReturn
+
+ while (true) {
+ (app: @annotation.switch) match {
+ case 0 => // applyK
+ k match {
+ case KReturn => return r.asInstanceOf[Option[(A,T[A])]]
+ case KUnsplit(sk2, fk2, k2) =>
+ r match {
+ case None => { app = 2; fk = fk2; k = k2 }
+ case Some((a2, t2)) => { app = 1; t = or(unit(a2), t2); sk = sk2; fk = fk2; k = k2 }
+ }
+ }
+
+ case 1 => // applyT
+ t match {
+ case Fail() => app = 2
+ case Unit(a2) => { a = a2; app = 3 }
+ case Or(t1, t2) => { t = t1; fk = FKOr(t2, sk, fk) }
+ case Bind(t2, f) => { t = t2; sk = SKBind(f, sk) }
+ case Apply(t2, f) => { t = t2; sk = SKApply(f, sk) }
+ case Filter(t2, p) => { t = t2; sk = SKFilter(p, sk) }
+ case Unsplit(fk2) => { app = 2; k = KUnsplit(sk, fk, k); fk = fk2 }
+ }
+
+ case 2 => // applyFK
+ fk match {
+ case FKOr(t2, sk2, fk2) => { app = 1; t = t2(); sk = sk2; fk = fk2 }
+ case FKSplit(r2) => { app = 0; r = r2 }
+ }
+
+ case 3 => // applySK
+ sk match {
+ case SKBind(f, sk2) => { app = 1; t = f(a); sk = sk2 }
+ case SKApply(f, sk2) => { sk = sk2; a = f(a) }
+ case SKFilter(p, sk2) => if (p(a)) sk = sk2 else app = 2
+ case SKSplit(rf) => { app = 0; r = rf(a, fk) }
+ }
+ }
+ }
+ throw new Exception("not reached")
+ }
+}
View
112 _code/scala-logic/LogicState.scala
@@ -19,7 +19,7 @@ trait LogicState { L =>
def runAcc(t: T[S,A], n: Int, acc: List[(S,A)]): List[(S,A)] =
if (n <= 0) acc.reverse else
split(s0, t) match {
- case None => Nil
+ case None => acc
case Some((s, a, t)) => runAcc(t, n - 1, (s, a) :: acc)
}
runAcc(t, n, Nil)
@@ -37,113 +37,3 @@ trait LogicState { L =>
implicit def syntax[S,A](t: T[S,A]) = Syntax(t)
}
-
-object LogicStateSFK extends LogicState {
- type FK[R] = () => R
- type SK[S,A,R] = (S, A, FK[R]) => R
-
- trait T[S,A] { def apply[R](s: S, sk: SK[S,A,R], fk: FK[R]): R }
-
- def fail[S,A] =
- new T[S,A] {
- def apply[R](s: S, sk: SK[S,A,R], fk: FK[R]) = fk()
- }
-
- def unit[S,A](a: A) =
- new T[S,A] {
- def apply[R](s: S, sk: SK[S,A,R], fk: FK[R]) = sk(s, a, fk)
- }
-
- def or[S,A](t1: T[S,A], t2: => T[S,A]) =
- new T[S,A] {
- def apply[R](s: S, sk: SK[S,A,R], fk: FK[R]) = t1(s, sk, { () => t2(s, sk, fk) })
- }
-
- def bind[S,A,B](t: T[S,A], f: A => T[S,B]) =
- new T[S,B] {
- def apply[R](s: S, sk: SK[S,B,R], fk: FK[R]) =
- t(s, ({ (s, a, fk) => f(a)(s, sk, fk) }: SK[S,A,R]), fk)
- }
-
- def apply[S,A,B](t: T[S,A], f: A => B) =
- new T[S,B] {
- def apply[R](s: S, sk: SK[S,B,R], fk: FK[R]) =
- t(s, ({ (s, a, fk) => sk(s, f(a), fk) }: SK[S,A,R]), fk)
- }
-
- def filter[S,A](t: T[S,A], p: A => Boolean) =
- new T[S,A] {
- def apply[R](s: S, sk: SK[S,A,R], fk: FK[R]) =
- t(s, ({ (s, a, fk) => if (p(a)) sk(s, a, fk) else fk() }: SK[S,A,R]), fk)
- }
-
- def split[S,A](s: S, t: T[S,A]) = {
- def stateUnit[S,A](s: S, a: A): T[S,A] =
- new T[S,A] {
- def apply[R](s: S, sk: SK[S,A,R], fk: FK[R]) = sk(s, a, fk)
- }
- def unsplit(r: () => Option[(S,A,T[S,A])]): T[S,A] =
- r() match {
- case None => fail
- case Some((s, a, t)) => or(stateUnit(s, a), t)
- }
- def sk : SK[S,A,Option[(S,A,T[S,A])]] =
- { (s, a, fk) => Some((s, a, unit(fk).flatMap(unsplit))) }
- t(s, sk, { () => None })
- }
-
- def get[S]: T[S,S] =
- new T[S,S] {
- def apply[R](s: S, sk: SK[S,S,R], fk: FK[R]) = sk(s, s, fk)
- }
-
- def set[S](s: S): T[S,Unit] =
- new T[S,Unit] {
- def apply[R](_s: S, sk: SK[S,Unit,R], fk: FK[R]) = sk(s, (), fk)
- }
-}
-
-object LogicStateSKE extends LogicState {
- type T[S,A] = (S, ((S, A) => Unit)) => Unit
-
- def fail[S,A] = { (s, sk) => throw Fail }
-
- def unit[S,A](a: A) = { (s, sk) => sk(s, a) }
-
- def or[S,A](t1: T[S,A], t2: => T[S,A]) =
- { (s, sk) =>
- try { t1(s, sk) }
- catch { case Fail => t2(s, sk) }
- }
-
- def bind[S,A,B](t: T[S,A], f: A => T[S,B]) =
- { (s, sk) => t(s, { (s, a) => f(a)(s, sk) }) }
-
- def apply[S,A,B](t: T[S,A], f: A => B) =
- { (s, sk) => t(s, { (s, a) => sk(s, f(a)) }) }
-
- def filter[S,A](t: T[S,A], p: A => Boolean) =
- { (s, sk) =>
- t(s, { (s, a) => if (p(a)) sk(s, a) else throw Fail })
- }
-
- def split[S,A](s: S, t: T[S,A]) = throw new Exception("unimplemented")
-
- override def run[S,A](s: S, t: T[S,A], n: Int): List[(S,A)] = {
- if (n <= 0) return Nil
- val lb = new scala.collection.mutable.ListBuffer[(S,A)]
- def sk(s: S, a: A) = {
- lb += ((s, a))
- throw (if (lb.size < n) Fail else Finish)
- }
- try {
- t(s, sk)
- throw new Exception("not reached")
- }
- catch { case Fail | Finish => lb.result }
- }
-
- def get[S] = { (s, sk) => sk(s, s) }
-
- def set[S](s: S) = { (_s, sk) => sk(s, ()) }
-}
View
64 _code/scala-logic/LogicStateSFK.scala
@@ -0,0 +1,64 @@
+object LogicStateSFK extends LogicState {
+ type FK[R] = () => R
+ type SK[S,A,R] = (S, A, FK[R]) => R
+
+ trait T[S,A] { def apply[R](s: S, sk: SK[S,A,R], fk: FK[R]): R }
+
+ def fail[S,A] =
+ new T[S,A] {
+ def apply[R](s: S, sk: SK[S,A,R], fk: FK[R]) = fk()
+ }
+
+ def unit[S,A](a: A) =
+ new T[S,A] {
+ def apply[R](s: S, sk: SK[S,A,R], fk: FK[R]) = sk(s, a, fk)
+ }
+
+ def or[S,A](t1: T[S,A], t2: => T[S,A]) =
+ new T[S,A] {
+ def apply[R](s: S, sk: SK[S,A,R], fk: FK[R]) = t1(s, sk, { () => t2(s, sk, fk) })
+ }
+
+ def bind[S,A,B](t: T[S,A], f: A => T[S,B]) =
+ new T[S,B] {
+ def apply[R](s: S, sk: SK[S,B,R], fk: FK[R]) =
+ t(s, ({ (s, a, fk) => f(a)(s, sk, fk) }: SK[S,A,R]), fk)
+ }
+
+ def apply[S,A,B](t: T[S,A], f: A => B) =
+ new T[S,B] {
+ def apply[R](s: S, sk: SK[S,B,R], fk: FK[R]) =
+ t(s, ({ (s, a, fk) => sk(s, f(a), fk) }: SK[S,A,R]), fk)
+ }
+
+ def filter[S,A](t: T[S,A], p: A => Boolean) =
+ new T[S,A] {
+ def apply[R](s: S, sk: SK[S,A,R], fk: FK[R]) =
+ t(s, ({ (s, a, fk) => if (p(a)) sk(s, a, fk) else fk() }: SK[S,A,R]), fk)
+ }
+
+ def split[S,A](s: S, t: T[S,A]) = {
+ def stateUnit[S,A](s: S, a: A): T[S,A] =
+ new T[S,A] {
+ def apply[R](s: S, sk: SK[S,A,R], fk: FK[R]) = sk(s, a, fk)
+ }
+ def unsplit(r: () => Option[(S,A,T[S,A])]): T[S,A] =
+ r() match {
+ case None => fail
+ case Some((s, a, t)) => or(stateUnit(s, a), t)
+ }
+ def sk : SK[S,A,Option[(S,A,T[S,A])]] =
+ { (s, a, fk) => Some((s, a, unit(fk).flatMap(unsplit))) }
+ t(s, sk, { () => None })
+ }
+
+ def get[S]: T[S,S] =
+ new T[S,S] {
+ def apply[R](s: S, sk: SK[S,S,R], fk: FK[R]) = sk(s, s, fk)
+ }
+
+ def set[S](s: S): T[S,Unit] =
+ new T[S,Unit] {
+ def apply[R](_s: S, sk: SK[S,Unit,R], fk: FK[R]) = sk(s, (), fk)
+ }
+}
View
65 _posts/2011-04-06-logic-programming-in-scala.markdown
@@ -431,10 +431,11 @@ trait Logic[T[_]] { L =>
// no abstract type T[A] but otherwise as before
}
{% endhighlight %}
-Neither alternative provides the expressivity of OCaml modules: with
-abstract types, consumers of `Logic` cannot return values of `T[A]`
-(as we saw above); with a type parameter, they can, but the
-type is no longer abstract.
+Neither alternative provides the expressivity of OCaml modules
+(*but see addendum below*):
+with abstract types, consumers of `Logic` cannot
+return values of `T[A]` (as we saw above); with a type parameter, they
+can, but the type is no longer abstract.
In OCaml we would write
{% highlight ocaml %}
@@ -453,3 +454,59 @@ struct
end
{% endhighlight %}
and get both the abstract type and the ability to return values of the type.
+
+*Addendum*
+
+Jorge Ortiz points out in the comments that it is possible to keep
+`T[A]` abstract and also return its values from `Bridge`, by making
+the `Logic` argument a (public) `val`. We can then remove the
+`private`s, and write `search` as just:
+
+{% highlight scala %}
+ def search: T[List[State]] = {
+ val start = List(State(Person.all, true, 60))
+ for { path <- tree(start); if path.head.left == Nil }
+ yield path
+ }
+{% endhighlight %}
+
+instead of baking `run` into it. Now, if we write
+`val b = new Bridge(LogicList)` then `b.search` has type
+`b.Logic.T[List[b.State]]`, and we can call `b.Logic.run` to evaluate
+it.
+
+This is only a modest improvement; what's still missing, compared to
+the OCaml version, is the fact that `LogicList` and `b.Logic` are the
+same module. So we can't call `LogicList.run(b.search)`
+directly. Worse, we can't compose modules which use the same `Logic`
+implementation, because they each have their own incompatibly-typed
+`Logic` member.
+
+I thought there might be a way out of this using singleton types---the
+idea is that a match of a value `v` against a typed pattern where the
+type is `w.type` succeeds when `v eq w` (section 8.2 in the reference
+manual). So we can define
+
+{% highlight scala %}
+def run[A](
+ Logic: Logic,
+ b: Bridge,
+ t: b.Logic.T[A],
+ n: Int): List[A] =
+{
+ Logic match {
+ case l : b.Logic.type => l.run(t, n)
+ }
+}
+{% endhighlight %}
+
+which is accepted, but sadly
+
+{% highlight scala %}
+scala> run[List[b.State]](LogicList, b, b.search, 2)
+<console>:8: error: type mismatch;
+ found : b.Logic.T[List[b.State]]
+ required: b.Logic.T[List[b.State]]
+ run[List[b.State]](LogicList, b, b.search, 2)
+ ^
+{% endhighlight %}
View
246 _posts/2011-04-14-logic-programming-in-scala-2.markdown
@@ -219,7 +219,7 @@ choice of alternatives no results are memoized; to compute each
successive number in `nat` all the previous ones must be
recomputed. So the running time of `run(nat, N)` is O(N<sup>2</sup>).
-<b>Tail recursion and heap space</b>
+<b>Tail recursion and defunctionalization</b>
The previous implementation isn't very efficient in Scala. One problem
is its use of continuation-passing style: because Scala doesn't
@@ -251,7 +251,7 @@ We can rewrite `run` with an accumulator to be tail-recursive:
def runAcc(t: T[A], n: Int, acc: List[A]): List[A] =
if (n <= 0) acc.reverse else
split(t) match {
- case None => Nil
+ case None => acc
case Some((a, t)) => runAcc(t, n - 1, a :: acc)
}
runAcc(t, n, Nil)
@@ -267,124 +267,158 @@ java.lang.StackOverflowError
...
{% endhighlight %}
-So Scala's local tail-call optimization is useful to reduce not just
-stack space, but also heap space. (We could of course write this as an
-ordinary loop instead.)
-
-<b>Backtracking with exceptions</b>
-
-The Kiselyov paper offers another implementation of the logic monad in
-terms of delimited continuations. This isn't quite helpful; while
-Scala implements delimited continuations, it does so by converting
-code to continuation-passing style (see Rompf et al.'s
-[Implementing First-Class Polymorphic Delimited Continuations by a Type-Directed Selective CPS-Transform](http://lamp.epfl.ch/~rompf/continuations-icfp09.pdf).
-So they suffer the same problem with un-eliminated tail calls.
-
-Still the delimited continuation implementation points toward another
-implementation using exceptions instead of failure continuations. The
-`prompt` and `abort` delimited control operators are similar to
-`catch` and `throw`---the first marks a point on the stack, the second
-unwinds the stack to that point. However, exceptions don't provide
-`shift` (which packages up a stack fragment as a function) so we'll
-need to hack around it.
-
-{% highlight scala %}
-object LogicSKE extends Logic {
- case object Fail extends Exception
-
- type T[A] = (A => Unit) => Unit
-{% endhighlight %}
-
-The type representing a choice among alternatives is now a function
-taking just a success continuation; failure is represented by throwing
-a `Fail` exception. We won't need to return values from the
-continuations (see `run` below) so we don't need to encode a rank-2
-type.
-
{% highlight scala %}
- def fail[A] = { sk => throw Fail }
-
- def unit[A](a: A) = { sk => sk(a) }
-{% endhighlight %}
-
-To fail we just throw `Fail`; to succeed with one alternative we just
-call the success continuation on the value.
+object LogicSFKDefunc extends Logic {
+ sealed trait T[A]
+ case class Fail[A]() extends T[A]
+ case class Unit[A](a: A) extends T[A]
+ case class Or[A](t1: T[A], t2: () => T[A]) extends T[A]
+ case class Bind[A,B](t: T[A], f: A => T[B]) extends T[B]
+ case class Apply[A,B](t: T[A], f: A => B) extends T[B]
+ case class Filter[A](t: T[A], p: A => Boolean) extends T[A]
+
+ sealed trait FK[R]
+ case class FKOr[A,R](t: () => T[A], sk: SK[A,R], fk: FK[R]) extends FK[R]
+ case class FKSplit[R](r: R) extends FK[R]
+
+ sealed trait SK[A,R]
+ case class SKBind[A,B,R](f: A => T[B], sk: SK[B,R]) extends SK[A,R]
+ case class SKApply[A,B,R](f: A => B, sk: SK[B,R]) extends SK[A,R]
+ case class SKFilter[A,R](p: A => Boolean, sk: SK[A,R]) extends SK[A,R]
+ case class SKSplit[A,R](r: (A, FK[R]) => R) extends SK[A,R]
+
+ def fail[A] = Fail()
+ def unit[A](a: A) = Unit(a)
+ def or[A](t1: T[A], t2: => T[A]) = Or(t1, { () => t2 })
+ def bind[A,B](t: T[A], f: A => T[B]) = Bind(t, f)
+ def apply[A,B](t: T[A], f: A => B) = Apply(t, f)
+ def filter[A](t: T[A], p: A => Boolean) = Filter(t, p)
-{% highlight scala %}
- def or[A](t1: T[A], t2: => T[A]) =
- { sk =>
- try { t1(sk) }
- catch { case Fail => t2(sk) }
- }
-{% endhighlight %}
+ def split[A](t: T[A]) = {
+ def unsplit[A](fk: FK[Option[(A, T[A])]]): T[A] =
+ applyFK(fk) match {
+ case None => fail
+ case Some((a, t)) => or(unit(a), t)
+ }
-We pass the success continuation first to `t1`; when `t2` runs out of
-alternatives and throws `Fail`, we catch it and pass the success
-continuation to `t2`. So The success continuation is called on each
-alternative in both `t1` and `t2`.
+ def applyT[A,R](t: T[A], sk: SK[A,R], fk: FK[R]): R =
+ t match {
+ case Fail() => applyFK(fk)
+ case Unit(a) => applySK(sk, a, fk)
+ case Or(t1, t2) => applyT(t1, sk, FKOr(t2, sk, fk))
+ case Bind(t, f) => applyT(t, SKBind(f, sk), fk)
+ case Apply(t, f) => applyT(t, SKApply(f, sk), fk)
+ case Filter(t, p) => applyT(t, SKFilter(p, sk), fk)
+ }
-{% highlight scala %}
- def bind[A,B](t: T[A], f: A => T[B]) =
- { sk => t(a => f(a)(sk)) }
+ def applyFK[R](fk: FK[R]): R =
+ fk match {
+ case FKOr(t, sk, fk) => applyT(t(), sk, fk)
+ case FKSplit(r) => r
+ }
- def apply[A,B](t: T[A], f: A => B) =
- { sk => t(a => sk(f(a))) }
+ def applySK[A,R](sk: SK[A,R], a: A, fk: FK[R]): R =
+ sk match {
+ case SKBind(f, sk) => applyT(f(a), sk, fk)
+ case SKApply(f, sk) => applySK(sk, f(a), fk)
+ case SKFilter(p, sk) => if (p(a)) applySK(sk, a, fk) else applyFK(fk)
+ case SKSplit(r) => r(a, fk)
+ }
- def filter[A](t: T[A], p: A => Boolean) =
- { sk =>
- t(a => if (p(a)) sk(a) else throw Fail)
- }
+ applyT[A,Option[(A,T[A])]](
+ t,
+ SKSplit((a, fk) => Some((a, bind(unit(fk), unsplit)))),
+ FKSplit(None))
+ }
+}
{% endhighlight %}
-`Bind` and `apply` are much the same as before, but without the
-failure continuations. `Filter` is also much the same, except that we
-throw `Fail` instead of calling a failure continuation when the
-predicate is not satisfied.
-
{% highlight scala %}
- def split[A](t: T[A]) = throw new Exception("unimplemented")
-
- case object Finish extends Exception
-
- override def run[A](t: T[A], n: Int): List[A] = {
- if (n <= 0) return Nil
- val lb = new scala.collection.mutable.ListBuffer[A]
- def sk(a: A) = {
- lb += a
- throw (if (lb.size < n) Fail else Finish)
- }
- try {
- t(sk)
- throw new Exception("not reached")
+object LogicSFKDefuncTailrec extends Logic {
+ sealed trait T[A]
+ case class Fail[A]() extends T[A]
+ case class Unit[A](a: A) extends T[A]
+ case class Or[A](t1: T[A], t2: () => T[A]) extends T[A]
+ case class Bind[A,B](t: T[A], f: A => T[B]) extends T[B]
+ case class Apply[A,B](t: T[A], f: A => B) extends T[B]
+ case class Filter[A](t: T[A], p: A => Boolean) extends T[A]
+ case class Unsplit[A](fk: FK) extends T[A]
+
+ type R = Option[(Any,T[Any])]
+
+ sealed trait FK
+ case class FKOr(t: () => T[Any], sk: SK, fk: FK) extends FK
+ case class FKSplit(r: R) extends FK
+
+ sealed trait SK
+ case class SKBind(f: Any => T[Any], sk: SK) extends SK
+ case class SKApply(f: Any => Any, sk: SK) extends SK
+ case class SKFilter(p: Any => Boolean, sk: SK) extends SK
+ case class SKSplit(r: (Any, FK) => R) extends SK
+
+ sealed trait K
+ case object KReturn extends K
+ case class KUnsplit(sk: SK, fk: FK, k: K) extends K
+
+ def fail[A] = Fail()
+ def unit[A](a: A) = Unit(a)
+ def or[A](t1: T[A], t2: => T[A]) = Or(t1, { () => t2 })
+ def bind[A,B](t: T[A], f: A => T[B]) = Bind(t, f)
+ def apply[A,B](t: T[A], f: A => B) = Apply(t, f)
+ def filter[A](t: T[A], p: A => Boolean) = Filter(t, p)
+
+ def split[A](t2: T[A]): Option[(A,T[A])] = {
+ var app = 1
+ var t = t2.asInstanceOf[T[Any]]
+ var a: Any = null
+ var r: R = null
+ var sk: SK = SKSplit((a, fk) => Some((a, Unsplit(fk))))
+ var fk: FK = FKSplit(None)
+ var k: K = KReturn
+
+ while (true) {
+ (app: @annotation.switch) match {
+ case 0 => // applyK
+ k match {
+ case KReturn => return r.asInstanceOf[Option[(A,T[A])]]
+ case KUnsplit(sk2, fk2, k2) =>
+ r match {
+ case None => { app = 2; fk = fk2; k = k2 }
+ case Some((a2, t2)) => { app = 1; t = or(unit(a2), t2); sk = sk2; fk = fk2; k = k2 }
+ }
+ }
+
+ case 1 => // applyT
+ t match {
+ case Fail() => app = 2
+ case Unit(a2) => { a = a2; app = 3 }
+ case Or(t1, t2) => { t = t1; fk = FKOr(t2, sk, fk) }
+ case Bind(t2, f) => { t = t2; sk = SKBind(f, sk) }
+ case Apply(t2, f) => { t = t2; sk = SKApply(f, sk) }
+ case Filter(t2, p) => { t = t2; sk = SKFilter(p, sk) }
+ case Unsplit(fk2) => { app = 2; k = KUnsplit(sk, fk, k); fk = fk2 }
+ }
+
+ case 2 => // applyFK
+ fk match {
+ case FKOr(t2, sk2, fk2) => { app = 1; t = t2(); sk = sk2; fk = fk2 }
+ case FKSplit(r2) => { app = 0; r = r2 }
+ }
+
+ case 3 => // applySK
+ sk match {
+ case SKBind(f, sk2) => { app = 1; t = f(a); sk = sk2 }
+ case SKApply(f, sk2) => { sk = sk2; a = f(a) }
+ case SKFilter(p, sk2) => if (p(a)) sk = sk2 else app = 2
+ case SKSplit(rf) => { app = 0; r = rf(a, fk) }
+ }
+ }
}
- catch { case Fail | Finish => lb.result }
+ throw new Exception("not reached")
}
}
{% endhighlight %}
-Here's where things get hacky. It's difficult to implement `split`
-using exceptions (see `LogicSKE2` in the
-[complete code](https://github.com/jaked/ambassadortothecomputers.blogspot.com/tree/master/_code/scala-logic)
-for an attempt---it works but is very slow). Instead we implement
-`run` directly: every time the success continuation is called we
-append the result to a mutable list. When we have enough results we
-throw `Finish` to stop generating them.
-
-(In the paper, `split` is used to implement search strategies other
-than the depth-first strategy we use here; if you want to play with
-those you can use `LogicSFK`.)
-
-Now we make better use of the stack:
-
-{% highlight scala %}
-scala> run(nat, 15000)
-res0: List[Int] = List(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, ...
-{% endhighlight %}
-
-(The size at which `run` blows up varies a lot between runs, even in
-the same instance of the Scala top-level. I guess this has to do with
-optimiziations performed by the JVM's JIT compiler.)
-
<b>State</b>
{% highlight scala %}
Please sign in to comment.
Something went wrong with that request. Please try again.