mirror of https://github.com/sbt/sbt.git
MList -> KList, Relation[T] -> Relation[A,B]
This commit is contained in:
parent
ff1657879c
commit
f1b5e0cf50
|
|
@ -7,23 +7,17 @@ import Types._
|
|||
|
||||
sealed trait HList
|
||||
{
|
||||
type ToM[M[_]] <: MList[M]
|
||||
type Up <: MList[Id]
|
||||
def up: Up
|
||||
type Wrap[M[_]] <: HList
|
||||
}
|
||||
sealed trait HNil extends HList
|
||||
{
|
||||
type ToM[M[_]] = MNil
|
||||
type Up = MNil
|
||||
def up = MNil
|
||||
type Wrap[M[_]] = HNil
|
||||
def :+: [G](g: G): G :+: HNil = HCons(g, this)
|
||||
}
|
||||
object HNil extends HNil
|
||||
final case class HCons[H, T <: HList](head : H, tail : T) extends HList
|
||||
{
|
||||
type ToM[M[_]] = MCons[H, tail.ToM[M], M]
|
||||
type Up = MCons[H, tail.Up, Id]
|
||||
def up = MCons[H,tail.Up, Id](head, tail.up)
|
||||
type Wrap[M[_]] = M[H] :+: T#Wrap[M]
|
||||
def :+: [G](g: G): G :+: H :+: T = HCons(g, this)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,47 @@
|
|||
/* sbt -- Simple Build Tool
|
||||
* Copyright 2010 Mark Harrah
|
||||
*/
|
||||
package sbt
|
||||
|
||||
import Types._
|
||||
|
||||
/** A higher-order heterogeneous list. It has a type constructor M[_] and
|
||||
* type parameters HL. The underlying data is M applied to each type parameter.
|
||||
* Explicitly tracking M[_] allows performing natural transformations or ensuring
|
||||
* all data conforms to some common type. */
|
||||
sealed trait KList[+M[_], HL <: HList] {
|
||||
type Raw = HL
|
||||
/** Transform to the underlying HList type.*/
|
||||
def down(implicit ev: M ~> Id): HL
|
||||
/** Apply a natural transformation. */
|
||||
def map[N[_]](f: M ~> N): KList[N, HL]
|
||||
/** Convert to a List. */
|
||||
def toList: List[M[_]]
|
||||
/** Convert to an HList. */
|
||||
def combine[N[X] >: M[X]]: HL#Wrap[N]
|
||||
}
|
||||
|
||||
final case class KCons[H, T <: HList, +M[_]](head: M[H], tail: KList[M,T]) extends KList[M, H :+: T] {
|
||||
def down(implicit f: M ~> Id) = HCons(f(head), tail.down(f))
|
||||
def map[N[_]](f: M ~> N) = KCons( f(head), tail.map(f) )
|
||||
// prepend
|
||||
def :^: [N[X] >: M[X], G](g: N[G]) = KCons(g, this)
|
||||
def toList = head :: tail.toList
|
||||
|
||||
def combine[N[X] >: M[X]]: (H :+: T)#Wrap[N] = HCons(head, tail.combine)
|
||||
}
|
||||
|
||||
sealed class KNil extends KList[Nothing, HNil] {
|
||||
def down(implicit f: Nothing ~> Id) = HNil
|
||||
def map[N[_]](f: Nothing ~> N) = KNil
|
||||
def :^: [M[_], H](h: M[H]) = KCons(h, this)
|
||||
def toList = Nil
|
||||
def combine[N[X]] = HNil
|
||||
}
|
||||
object KNil extends KNil
|
||||
|
||||
object KList
|
||||
{
|
||||
// nicer alias for pattern matching
|
||||
val :^: = KCons
|
||||
}
|
||||
|
|
@ -1,51 +0,0 @@
|
|||
/* sbt -- Simple Build Tool
|
||||
* Copyright 2010 Mark Harrah
|
||||
*/
|
||||
package sbt
|
||||
|
||||
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]
|
||||
|
||||
def toList: List[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) )
|
||||
|
||||
def :^: [N[X] >: M[X], G](g: N[G]): MCons[G, MCons[H, T, N], N] = MCons(g, this)
|
||||
|
||||
def toList = head :: tail.toList
|
||||
}
|
||||
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
|
||||
|
||||
def :^: [M[_], H](h: M[H]): MCons[H, MNil, M] = MCons(h, this)
|
||||
|
||||
def toList = Nil
|
||||
}
|
||||
object MNil extends MNil
|
||||
|
||||
|
||||
object MList
|
||||
{
|
||||
implicit def fromTCList[A[_]](list: Traversable[A[_]]): MList[A] = ((MNil: MList[A]) /: list) ( (hl,v) => MCons(v, hl) )
|
||||
implicit def fromList[A](list: Traversable[A]): MList[Const[A]#Apply] = ((MNil: MList[Const[A]#Apply]) /: list) ( (hl,v) => MCons[A, hl.type, Const[A]#Apply](v, hl) )
|
||||
}
|
||||
|
|
@ -6,72 +6,72 @@ package sbt
|
|||
object Relation
|
||||
{
|
||||
/** Constructs a new immutable, finite relation that is initially empty. */
|
||||
def empty[T]: Relation[T] = new MRelation[T](Map.empty, Map.empty)
|
||||
def empty[A,B]: Relation[A,B] = new MRelation[A,B](Map.empty, Map.empty)
|
||||
}
|
||||
/** Binary relation on T. It is a set of pairs (_1, _2) for _1, _2 in T. */
|
||||
trait Relation[T]
|
||||
/** Binary relation between A and B. It is a set of pairs (_1, _2) for _1 in A, _2 in B. */
|
||||
trait Relation[A,B]
|
||||
{
|
||||
/** Returns the set of all _2s such that (_1, _2) is in this relation. */
|
||||
def forward(_1: T): Set[T]
|
||||
def forward(_1: A): Set[B]
|
||||
/** Returns the set of all _1s such that (_1, _2) is in this relation. */
|
||||
def reverse(_2: T): Set[T]
|
||||
def reverse(_2: B): Set[A]
|
||||
/** Includes the relation given by `pair`. */
|
||||
def +(pair: (T, T)): Relation[T]
|
||||
def +(pair: (A, B)): Relation[A,B]
|
||||
/** Includes the relation (a, b). */
|
||||
def +(a: T, b: T): Relation[T]
|
||||
def +(a: A, b: B): Relation[A,B]
|
||||
/** Includes the relations (a, b) for all b in bs. */
|
||||
def +(a: T, bs: Iterable[T]): Relation[T]
|
||||
def +(a: A, bs: Iterable[B]): Relation[A,B]
|
||||
/** Returns the union of the relation r with this relation. */
|
||||
def ++(r: Relation[T]): Relation[T]
|
||||
def ++(r: Relation[A,B]): Relation[A,B]
|
||||
/** Includes the given relations. */
|
||||
def ++(rs: Iterable[(T,T)]): Relation[T]
|
||||
def ++(rs: Iterable[(A,B)]): Relation[A,B]
|
||||
/** Removes all relations (_1, _2) for all _1 in _1s. */
|
||||
def --(_1s: Iterable[T]): Relation[T]
|
||||
def --(_1s: Iterable[A]): Relation[A,B]
|
||||
/** Removes all `pairs` from this relation. */
|
||||
def --(pairs: Traversable[(T,T)]): Relation[T]
|
||||
def --(pairs: Traversable[(A,B)]): Relation[A,B]
|
||||
/** Removes all pairs (_1, _2) from this relation. */
|
||||
def -(_1: T): Relation[T]
|
||||
def -(_1: A): Relation[A,B]
|
||||
/** Removes `pair` from this relation. */
|
||||
def -(pair: (T,T)): Relation[T]
|
||||
def -(pair: (A,B)): Relation[A,B]
|
||||
/** Returns the set of all _1s such that (_1, _2) is in this relation. */
|
||||
def _1s: collection.Set[T]
|
||||
def _1s: collection.Set[A]
|
||||
/** Returns the set of all _2s such that (_1, _2) is in this relation. */
|
||||
def _2s: collection.Set[T]
|
||||
def _2s: collection.Set[B]
|
||||
|
||||
/** Returns all pairs in this relation.*/
|
||||
def all: Traversable[(T,T)]
|
||||
def all: Traversable[(A,B)]
|
||||
|
||||
def forwardMap: Map[T, Set[T]]
|
||||
def reverseMap: Map[T, Set[T]]
|
||||
def forwardMap: Map[A, Set[B]]
|
||||
def reverseMap: Map[B, Set[A]]
|
||||
}
|
||||
private final class MRelation[T](fwd: Map[T, Set[T]], rev: Map[T, Set[T]]) extends Relation[T]
|
||||
private final class MRelation[A,B](fwd: Map[A, Set[B]], rev: Map[B, Set[A]]) extends Relation[A,B]
|
||||
{
|
||||
type M = Map[T, Set[T]]
|
||||
type M[X,Y] = Map[X, Set[Y]]
|
||||
|
||||
def forwardMap = fwd
|
||||
def reverseMap = rev
|
||||
|
||||
def forward(t: T) = get(fwd, t)
|
||||
def reverse(t: T) = get(rev, t)
|
||||
def forward(t: A) = get(fwd, t)
|
||||
def reverse(t: B) = get(rev, t)
|
||||
|
||||
def _1s = fwd.keySet
|
||||
def _2s = rev.keySet
|
||||
|
||||
def all: Traversable[(T,T)] = fwd.iterator.flatMap { case (a, bs) => bs.iterator.map( b => (a,b) ) }.toTraversable
|
||||
def all: Traversable[(A,B)] = fwd.iterator.flatMap { case (a, bs) => bs.iterator.map( b => (a,b) ) }.toTraversable
|
||||
|
||||
def +(pair: (T, T)): Relation[T] = this + (pair._1, Set(pair._2))
|
||||
def +(from: T, to: T): Relation[T] = this + (from, Set(to))
|
||||
def +(from: T, to: Iterable[T]): Relation[T] =
|
||||
def +(pair: (A,B)) = this + (pair._1, Set(pair._2))
|
||||
def +(from: A, to: B) = this + (from, Set(to))
|
||||
def +(from: A, to: Iterable[B]) =
|
||||
new MRelation( add(fwd, from, to), (rev /: to) { (map, t) => add(map, t, Seq(from)) })
|
||||
|
||||
def ++(rs: Iterable[(T,T)]): Relation[T] = ((this: Relation[T]) /: rs) { _ + _ }
|
||||
def ++(other: Relation[T]): Relation[T] = new MRelation[T]( combine(fwd, other.forwardMap), combine(rev, other.reverseMap) )
|
||||
def ++(rs: Iterable[(A,B)]) = ((this: Relation[A,B]) /: rs) { _ + _ }
|
||||
def ++(other: Relation[A,B]) = new MRelation[A,B]( combine(fwd, other.forwardMap), combine(rev, other.reverseMap) )
|
||||
|
||||
def --(ts: Iterable[T]): Relation[T] = ((this: Relation[T]) /: ts) { _ - _ }
|
||||
def --(pairs: Traversable[(T,T)]): Relation[T] = ((this: Relation[T]) /: pairs) { _ - _ }
|
||||
def -(pair: (T,T)): Relation[T] =
|
||||
def --(ts: Iterable[A]): Relation[A,B] = ((this: Relation[A,B]) /: ts) { _ - _ }
|
||||
def --(pairs: Traversable[(A,B)]): Relation[A,B] = ((this: Relation[A,B]) /: pairs) { _ - _ }
|
||||
def -(pair: (A,B)): Relation[A,B] =
|
||||
new MRelation( remove(fwd, pair._1, pair._2), remove(rev, pair._2, pair._1) )
|
||||
def -(t: T): Relation[T] =
|
||||
def -(t: A): Relation[A,B] =
|
||||
fwd.get(t) match {
|
||||
case Some(rs) =>
|
||||
val upRev = (rev /: rs) { (map, r) => remove(map, r, t) }
|
||||
|
|
@ -79,7 +79,7 @@ private final class MRelation[T](fwd: Map[T, Set[T]], rev: Map[T, Set[T]]) exten
|
|||
case None => this
|
||||
}
|
||||
|
||||
private def remove(map: M, from: T, to: T): M =
|
||||
private def remove[X,Y](map: M[X,Y], from: X, to: Y): M[X,Y] =
|
||||
map.get(from) match {
|
||||
case Some(tos) =>
|
||||
val newSet = tos - to
|
||||
|
|
@ -87,13 +87,13 @@ private final class MRelation[T](fwd: Map[T, Set[T]], rev: Map[T, Set[T]]) exten
|
|||
case None => map
|
||||
}
|
||||
|
||||
private def combine(a: M, b: M): M =
|
||||
private def combine[X,Y](a: M[X,Y], b: M[X,Y]): M[X,Y] =
|
||||
(a /: b) { (map, mapping) => add(map, mapping._1, mapping._2) }
|
||||
|
||||
private[this] def add(map: M, from: T, to: Iterable[T]): M =
|
||||
private[this] def add[X,Y](map: M[X,Y], from: X, to: Iterable[Y]): M[X,Y] =
|
||||
map.updated(from, get(map, from) ++ to)
|
||||
|
||||
private[this] def get(map: M, t: T): Set[T] = map.getOrElse(t, Set.empty[T])
|
||||
private[this] def get[X,Y](map: M[X,Y], t: X): Set[Y] = map.getOrElse(t, Set.empty[Y])
|
||||
|
||||
override def toString = all.mkString("Relation [", ", ", "]")
|
||||
}
|
||||
|
|
@ -5,7 +5,7 @@ package sbt
|
|||
|
||||
object Types extends TypeFunctions
|
||||
{
|
||||
val :^: = MCons
|
||||
val :^: = KCons
|
||||
val :+: = HCons
|
||||
type :+:[H, T <: HList] = HCons[H,T]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,15 +5,15 @@ package sbt
|
|||
|
||||
import Types._
|
||||
|
||||
object MTest {
|
||||
object KTest {
|
||||
val f = new (Option ~> List) { def apply[T](o: Option[T]): List[T] = o.toList }
|
||||
|
||||
val x = Some(3) :^: Some("asdf") :^: MNil
|
||||
val x = Some(3) :^: Some("asdf") :^: KNil
|
||||
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 m1a = y match { case List(3) :^: List("asdf") :^: KNil => println("true") }
|
||||
val m1b = (List(3) :^: KNil) match { case yy :^: KNil => println("true") }
|
||||
|
||||
val head = new (List ~> Id) { def apply[T](xs: List[T]): T = xs.head }
|
||||
val z = y.map[Id](head).down
|
||||
val z = y down head
|
||||
val m2 = z match { case 3 :+: "asdf" :+: HNil => println("true") }
|
||||
}
|
||||
|
|
@ -11,7 +11,7 @@ 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 x = Some(3) :^: Some("asdf") :^: KNil
|
||||
val y = x.map[Id](mp)
|
||||
val z = y.down
|
||||
z match { case 9 :+: "a" :+: HNil => println("true") }
|
||||
|
|
|
|||
|
|
@ -8,11 +8,11 @@ import Prop._
|
|||
|
||||
object RelationTest extends Properties("Relation")
|
||||
{
|
||||
property("Added entry check") = forAll { (pairs: List[(Int, Int)]) =>
|
||||
val r = Relation.empty[Int] ++ pairs
|
||||
property("Added entry check") = forAll { (pairs: List[(Int, Double)]) =>
|
||||
val r = Relation.empty[Int, Double] ++ pairs
|
||||
check(r, pairs)
|
||||
}
|
||||
def check(r: Relation[Int], pairs: Seq[(Int, Int)]) =
|
||||
def check(r: Relation[Int, Double], pairs: Seq[(Int, Double)]) =
|
||||
{
|
||||
val _1s = pairs.map(_._1).toSet
|
||||
val _2s = pairs.map(_._2).toSet
|
||||
|
|
@ -27,15 +27,15 @@ object RelationTest extends Properties("Relation")
|
|||
}
|
||||
}
|
||||
|
||||
property("Does not contain removed entries") = forAll { (pairs: List[(Int, Int, Boolean)]) =>
|
||||
property("Does not contain removed entries") = forAll { (pairs: List[(Int, Double, Boolean)]) =>
|
||||
val add = pairs.map { case (a,b,c) => (a,b) }
|
||||
val added = Relation.empty[Int] ++ add
|
||||
val added = Relation.empty[Int, Double] ++ add
|
||||
|
||||
val removeFine = pairs.collect { case (a,b,true) => (a,b) }
|
||||
val removeCoarse = removeFine.map(_._1)
|
||||
val r = added -- removeCoarse
|
||||
|
||||
def notIn[T](map: Map[T, Set[T]], a: T, b: T) = map.get(a).forall(set => ! (set contains b) )
|
||||
def notIn[X,Y](map: Map[X, Set[Y]], a: X, b: Y) = map.get(a).forall(set => ! (set contains b) )
|
||||
|
||||
all(removeCoarse) { rem =>
|
||||
("_1s does not contain removed" |: (!r._1s.contains(rem)) ) &&
|
||||
|
|
@ -56,12 +56,12 @@ object RelationTest extends Properties("Relation")
|
|||
|
||||
object EmptyRelationTest extends Properties("Empty relation")
|
||||
{
|
||||
lazy val e = Relation.empty[Int]
|
||||
lazy val e = Relation.empty[Int, Double]
|
||||
|
||||
property("Forward empty") = forAll { (i: Int) => e.forward(i).isEmpty }
|
||||
property("Reverse empty") = forAll { (i: Int) => e.reverse(i).isEmpty }
|
||||
property("Forward map empty") = forAll { (i: Int) => e.forwardMap.isEmpty }
|
||||
property("Reverse map empty") = forAll { (i: Int) => e.reverseMap.isEmpty }
|
||||
property("_1 empty") = forAll { (i: Int) => e._1s.isEmpty }
|
||||
property("_2 empty") = forAll { (i: Int) => e._2s.isEmpty }
|
||||
property("Reverse empty") = forAll { (i: Double) => e.reverse(i).isEmpty }
|
||||
property("Forward map empty") = e.forwardMap.isEmpty
|
||||
property("Reverse map empty") = e.reverseMap.isEmpty
|
||||
property("_1 empty") = e._1s.isEmpty
|
||||
property("_2 empty") = e._2s.isEmpty
|
||||
}
|
||||
Loading…
Reference in New Issue