graph evaluator, rewrite, general updates

This commit is contained in:
Mark Harrah 2010-06-07 08:53:21 -04:00
parent b1bb6ce5ec
commit 1144fb5a27
11 changed files with 299 additions and 11 deletions

View File

@ -0,0 +1,45 @@
/* sbt -- Simple Build Tool
* Copyright 2010 Mark Harrah
*/
package sbt
/** A mutable set interface that uses object identity to test for set membership.*/
trait IDSet[T]
{
def apply(t: T): Boolean
def contains(t: T): Boolean
def += (t: T): Unit
def ++=(t: Iterable[T]): Unit
def -= (t: T): Boolean
def all: collection.Iterable[T]
def isEmpty: Boolean
def foreach(f: T => Unit): Unit
def process[S](t: T)(ifSeen: S)(ifNew: => S): S
}
object IDSet
{
implicit def toTraversable[T]: IDSet[T] => Traversable[T] = _.all
def apply[T](values: T*): IDSet[T] = apply(values)
def apply[T](values: Iterable[T]): IDSet[T] =
{
val s = create[T]
s ++= values
s
}
def create[T]: IDSet[T] = new IDSet[T] {
private[this] val backing = new java.util.IdentityHashMap[T, AnyRef]
private[this] val Dummy: AnyRef = ""
def apply(t: T) = contains(t)
def contains(t: T) = backing.containsKey(t)
def foreach(f: T => Unit) = all foreach f
def += (t: T) = backing.put(t, Dummy)
def ++=(t: Iterable[T]) = t foreach +=
def -= (t:T) = if(backing.remove(t) eq null) false else true
def all = collection.JavaConversions.asIterable(backing.keySet)
def isEmpty = backing.isEmpty
def process[S](t: T)(ifSeen: S)(ifNew: => S) = if(contains(t)) ifSeen else { this += t ; ifNew }
override def toString = backing.toString
}
}

View File

@ -7,6 +7,11 @@ import Types._
sealed trait MList[+M[_]]
{
// For converting MList[Id] to an HList
// This is useful because type inference doesn't work well with Id
type Raw <: HList
def down(implicit ev: M ~> Id): Raw
type Map[N[_]] <: MList[N]
def map[N[_]](f: M ~> N): Map[N]
@ -14,6 +19,9 @@ sealed trait MList[+M[_]]
}
final case class MCons[H, +T <: MList[M], +M[_]](head: M[H], tail: T) extends MList[M]
{
type Raw = H :+: tail.Raw
def down(implicit f: M ~> Id): Raw = HCons(f(head), tail.down(f))
type Map[N[_]] = MCons[H, tail.Map[N], N]
def map[N[_]](f: M ~> N) = MCons( f(head), tail.map(f) )
@ -23,6 +31,9 @@ final case class MCons[H, +T <: MList[M], +M[_]](head: M[H], tail: T) extends ML
}
sealed class MNil extends MList[Nothing]
{
type Raw = HNil
def down(implicit f: Nothing ~> Id) = HNil
type Map[N[_]] = MNil
def map[N[_]](f: Nothing ~> N) = MNil
@ -30,4 +41,4 @@ sealed class MNil extends MList[Nothing]
def toList = Nil
}
object MNil extends MNil
object MNil extends MNil

View File

@ -0,0 +1,43 @@
/* sbt -- Simple Build Tool
* Copyright 2010 Mark Harrah
*/
package sbt
import Types._
trait PMap[K[_], V[_]] extends (K ~> V)
{
def apply[T](k: K[T]): V[T]
def get[T](k: K[T]): Option[V[T]]
def update[T](k: K[T], v: V[T]): Unit
def contains[T](k: K[T]): Boolean
def remove[T](k: K[T]): Option[V[T]]
def getOrUpdate[T](k: K[T], make: => V[T]): V[T]
}
object PMap
{
implicit def toFunction[K[_], V[_]](map: PMap[K,V]): K[_] => V[_] = k => map(k)
}
abstract class AbstractPMap[K[_], V[_]] extends PMap[K,V]
{
def apply[T](k: K[T]): V[T] = get(k).get
def contains[T](k: K[T]): Boolean = get(k).isDefined
}
import collection.mutable.Map
/** Only suitable for K that is invariant in its parameter.
* Option and List keys are not, for example, because None <:< Option[String] and None <: Option[Int].*/
class DelegatingPMap[K[_], V[_]](backing: Map[K[_], V[_]]) extends AbstractPMap[K,V]
{
def get[T](k: K[T]): Option[V[T]] = cast[T]( backing.get(k) )
def update[T](k: K[T], v: V[T]) { backing(k) = v }
def remove[T](k: K[T]) = cast( backing.remove(k) )
def getOrUpdate[T](k: K[T], make: => V[T]) = cast[T]( backing.getOrElseUpdate(k, make) )
private[this] def cast[T](v: V[_]): V[T] = v.asInstanceOf[V[T]]
private[this] def cast[T](o: Option[V[_]]): Option[V[T]] = o map cast[T]
override def toString = backing.toString
}

View File

@ -0,0 +1,31 @@
/* sbt -- Simple Build Tool
* Copyright 2010 Mark Harrah
*/
package sbt
import Types._
// Used to emulate ~> literals
trait Param[A[_], B[_]]
{
type T
def in: A[T]
def ret(out: B[T])
def ret: B[T]
}
object Param
{
implicit def pToT[A[_], B[_]](p: Param[A,B] => Unit): A~>B = new (A ~> B) {
def apply[s](a: A[s]): B[s] = {
val v: Param[A,B] { type T = s} = new Param[A,B] { type T = s
def in = a
private var r: B[T] = _
def ret(b: B[T]) {r = b}
def ret: B[T] = r
}
p(v)
v.ret
}
}
}

View File

@ -0,0 +1,42 @@
/* sbt -- Simple Build Tool
* Copyright 2010 Mark Harrah
*/
package sbt
import Types._
trait Rewrite[A[_]]
{
def apply[T](node: A[T], rewrite: Rewrite[A]): A[T]
}
object Rewrite
{
def Id[A[_]]: Rewrite[A] = new Rewrite[A] { def apply[T](node: A[T], rewrite: Rewrite[A]) = node }
implicit def specificF[T](f: T => T): Rewrite[Const[T]#Apply] = new Rewrite[Const[T]#Apply] {
def apply[S](node:T, rewrite: Rewrite[Const[T]#Apply]): T = f(node)
}
implicit def pToRewrite[A[_]](p: Param[A,A] => Unit): Rewrite[A] = toRewrite(Param.pToT(p))
implicit def toRewrite[A[_]](f: A ~> A): Rewrite[A] = new Rewrite[A] {
def apply[T](node: A[T], rewrite:Rewrite[A]) = f(node)
}
def compose[A[_]](a: Rewrite[A], b: Rewrite[A]): Rewrite[A] =
new Rewrite[A] {
def apply[T](node: A[T], rewrite: Rewrite[A]) =
a(b(node, rewrite), rewrite)
}
implicit def rewriteOps[A[_]](outer: Rewrite[A]): RewriteOps[A] =
new RewriteOps[A] {
def (g: A ~> A): Rewrite[A] = compose(outer, g)
def andThen(g: A ~> A): Rewrite[A] = compose(g, outer)
def (g: Rewrite[A]): Rewrite[A] = compose(outer, g)
def andThen(g: Rewrite[A]): Rewrite[A] = compose(g, outer)
}
def apply[A[_], T](value: A[T])(implicit rewrite: Rewrite[A]): A[T] = rewrite(value, rewrite)
}
trait RewriteOps[A[_]]
{
def andThen(g: A ~> A): Rewrite[A]
def (g: A ~> A): Rewrite[A]
def (g: Rewrite[A]): Rewrite[A]
}

View File

@ -7,14 +7,26 @@ trait TypeFunctions
{
type Id[X] = X
trait Const[A] { type Apply[B] = A }
trait P1of2[M[_,_], A] { type Apply[B] = M[A,B] }
trait Down[M[_]] { type Apply[B] = Id[M[B]] }
trait Compose[A[_], B[_]] { type Apply[T] = A[B[T]] }
trait P1of2[M[_,_], A] { type Apply[B] = M[A,B]; type Flip[B] = M[B, A] }
trait ~>[-A[_], +B[_]]
{
def apply[T](a: A[T]): B[T]
}
def Id: Id ~> Id =
new (Id ~> Id) { def apply[T](a: T): T = a }
final val left = new (Id ~> P1of2[Left, Nothing]#Flip) { def apply[T](t: T) = Left(t) }
final val right = new (Id ~> P1of2[Right, Nothing]#Apply) { def apply[T](t: T) = Right(t) }
final val some = new (Id ~> Some) { def apply[T](t: T) = Some(t) }
}
object TypeFunctions extends TypeFunctions
object TypeFunctions extends TypeFunctions
trait ~>[-A[_], +B[_]]
{ outer =>
def apply[T](a: A[T]): B[T]
// directly on ~> because of type inference limitations
final def [C[_]](g: C ~> A): C ~> B = new (C ~> B) { def apply[T](c: C[T]) = outer.apply(g(c)) }
final def [C,D](g: C => D)(implicit ev: D <:< A[D]): C => B[D] = i => apply(ev(g(i)) )
final def fn[T] = (t: A[T]) => apply[T](t)
}
object ~>
{
import TypeFunctions._
val Id: Id ~> Id = new (Id ~> Id) { def apply[T](a: T): T = a }
implicit def tcIdEquals: (Id ~> Id) = Id
}

View File

@ -8,4 +8,4 @@ object Types extends TypeFunctions
val :^: = MCons
val :+: = HCons
type :+:[H, T <: HList] = HCons[H,T]
}
}

View File

@ -0,0 +1,17 @@
/* sbt -- Simple Build Tool
* Copyright 2010 Mark Harrah
*/
package sbt
import Types._
// compilation test
object LiteralTest {
def x[A[_],B[_]](f: A ~> B) = f
import Param._
val f = x { (p: Param[Option,List]) => p.ret( p.in.toList ) }
val a: List[Int] = f( Some(3) )
val b: List[String] = f( Some("aa") )
}

View File

@ -0,0 +1,19 @@
/* sbt -- Simple Build Tool
* Copyright 2010 Mark Harrah
*/
package sbt
import Types._
object MTest {
val f = new (Option ~> List) { def apply[T](o: Option[T]): List[T] = o.toList }
val x = Some(3) :^: Some("asdf") :^: MNil
val y = x map f
val m1a = y match { case List(3) :^: List("asdf") :^: MNil => println("true") }
val m1b = (List(3) :^: MNil) match { case yy :^: MNil => println("true") }
val head = new (List ~> Id) { def apply[T](xs: List[T]): T = xs.head }
val z = y.map[Id](head).down
val m2 = z match { case 3 :+: "asdf" :+: HNil => println("true") }
}

View File

@ -0,0 +1,18 @@
/* sbt -- Simple Build Tool
* Copyright 2010 Mark Harrah
*/
package sbt
import Types._
// compilation test
object PMapTest
{
val mp = new DelegatingPMap[Some, Id](new collection.mutable.HashMap)
mp(Some("asdf")) = "a"
mp(Some(3)) = 9
val x = Some(3) :^: Some("asdf") :^: MNil
val y = x.map[Id](mp)
val z = y.down
z match { case 9 :+: "a" :+: HNil => println("true") }
}

View File

@ -0,0 +1,50 @@
/* sbt -- Simple Build Tool
* Copyright 2010 Mark Harrah
*/
package sbt
import Types._
object RewriteTest
{
// dist and add0 show the awkwardness when not just manipulating superstructure:
// would have to constrain the parameters to Term to be instances of Zero/Eq somehow
val dist: Rewrite[Term] = (p: Param[Term, Term]) => p.ret( p.in match {
case Add(Mult(a,b),Mult(c,d)) if a == c=> Mult(a, Add(b,d))
case x => x
})
val add0: Rewrite[Term] = (p: Param[Term, Term]) => p.ret( p.in match {
case Add(V(0), y) => y
case Add(x, V(0)) => x
case x => x
})
val rewriteBU= new Rewrite[Term] {
def apply[T](node: Term[T], rewrite: Rewrite[Term]) = {
def r[T](node: Term[T]) = rewrite(node, rewrite)
node match {
case Add(x, y) => Add(r(x), r(y))
case Mult(x, y) => Mult(r(x), r(y))
case x => x
}
}
}
val d2 = dist add0 rewriteBU
implicit def toV(t: Int): V[Int] = V(t)
implicit def toVar(s: String): Var[Int] = Var[Int](s)
val t1: Term[Int] = Add(Mult(3,4), Mult(4, 5))
val t2: Term[Int] = Add(Mult(4,4), Mult(4, 5))
val t3: Term[Int] = Add(Mult(Add("x", 0),4), Mult("x", 5))
println( Rewrite(t1)(d2) )
println( Rewrite(t2)(d2) )
println( Rewrite(t3)(d2) )
}
sealed trait Term[T]
final case class Add[T](a: Term[T], b: Term[T]) extends Term[T]
final case class Mult[T](a: Term[T], b: Term[T]) extends Term[T]
final case class V[T](v: T) extends Term[T]
final case class Var[T](name: String) extends Term[T]