diff --git a/tasks/Execute.scala b/tasks/Execute.scala index 3189bc079..b471d8aa3 100644 --- a/tasks/Execute.scala +++ b/tasks/Execute.scala @@ -206,7 +206,7 @@ final class Execute[A[_] <: AnyRef](checkCycles: Boolean)(implicit view: A ~> No def submit[T]( node: A[T] )(implicit strategy: Strategy) { val v = view(node) - val rs: v.Mixed#Map[Result] = v.mixedIn.map(results) + val rs = v.mixedIn.map(results) val ud = v.uniformIn.map(results.apply[v.Uniform]) strategy.submit( node, () => work(node, v.work(rs, ud)) ) } diff --git a/tasks/Node.scala b/tasks/Node.scala index 91c8f54ec..c26faf5a7 100644 --- a/tasks/Node.scala +++ b/tasks/Node.scala @@ -7,12 +7,11 @@ import Types._ trait Node[A[_], T] { - type Mixed <: MList[A] - type MixedResults = Mixed#Map[Result] + type Mixed <: HList type Uniform - val mixedIn: Mixed + val mixedIn: KList[A, Mixed] val uniformIn: Seq[A[Uniform]] - def work(mixed: MixedResults, uniform: Seq[Result[Uniform]]): Either[A[T], T] + def work(mixed: KList[Result, Mixed], uniform: Seq[Result[Uniform]]): Either[A[T], T] } diff --git a/tasks/src/test/scala/DemoTask.scala b/tasks/src/test/scala/DemoTask.scala index 1574c4240..b59670967 100644 --- a/tasks/src/test/scala/DemoTask.scala +++ b/tasks/src/test/scala/DemoTask.scala @@ -9,21 +9,21 @@ import Execute._ sealed trait Task[+T] sealed case class Pure[+T](eval: () => T) extends Task[T] -final case class Mapped[+T, In <: MList[Task]](in: In, f: In#Map[Result] => T) extends Task[T] -final case class MapAll[+T, In <: MList[Task]](in: In, f: In#Map[Result]#Raw => T) extends Task[T] -final case class FlatMapAll[+T, In <: MList[Task]](in: In, f: In#Map[Result]#Raw => Task[T]) extends Task[T] -final case class MapFailure[+T, In <: MList[Task]](in: In, f: Seq[Incomplete] => T) extends Task[T] -final case class FlatMapFailure[+T, In <: MList[Task]](in: In, f: Seq[Incomplete] => Task[T]) extends Task[T] -final case class FlatMapped[+T, In <: MList[Task]](in: In, f: In#Map[Result] => Task[T]) extends Task[T] +final case class Mapped[+T, In <: HList](in: Tasks[In], f: Results[In] => T) extends Task[T] +final case class MapAll[+T, In <: HList](in: Tasks[In], f: In => T) extends Task[T] +final case class FlatMapAll[+T, In <: HList](in: Tasks[In], f: In => Task[T]) extends Task[T] +final case class MapFailure[+T, In <: HList](in: Tasks[In], f: Seq[Incomplete] => T) extends Task[T] +final case class FlatMapFailure[+T, In <: HList](in: Tasks[In], f: Seq[Incomplete] => Task[T]) extends Task[T] +final case class FlatMapped[+T, In <: HList](in: Tasks[In], f: Results[In] => Task[T]) extends Task[T] final case class DependsOn[+T](in: Task[T], deps: Seq[Task[_]]) extends Task[T] final case class Join[+T, U](in: Seq[Task[U]], f: Seq[U] => Either[Task[T], T]) extends Task[T] { type Uniform = U } -trait MultiInTask[M <: MList[Task]] +trait MultiInTask[In <: HList] { - def flatMap[T](f: M#Map[Result]#Raw => Task[T]): Task[T] - def flatMapR[T](f: M#Map[Result] => Task[T]): Task[T] - def mapH[T](f: M#Map[Result]#Raw => T): Task[T] - def mapR[T](f: M#Map[Result] => T): Task[T] + def flatMap[T](f: In => Task[T]): Task[T] + def flatMapR[T](f: Results[In] => Task[T]): Task[T] + def mapH[T](f: In => T): Task[T] + def mapR[T](f: Results[In] => T): Task[T] def flatFailure[T](f: Seq[Incomplete] => Task[T]): Task[T] def mapFailure[T](f: Seq[Incomplete] => T): Task[T] } @@ -48,6 +48,9 @@ trait JoinTask[S, CC[_]] } object Task { + type Tasks[HL <: HList] = KList[Task, HL] + type Results[HL <: HList] = KList[Result, HL] + def pure[T](f: => T): Task[T] = toPure(f _) def pure[T](name: String, f: => T): Task[T] = new Pure(f _) { override def toString = name } implicit def toPure[T](f: () => T): Task[T] = new Pure(f) @@ -66,23 +69,24 @@ object Task } - implicit def multInputTask[M <: MList[Task]](ml: M): MultiInTask[M] = new MultiInTask[M] { - def flatMap[T](f: M#Map[Result]#Raw => Task[T]): Task[T] = new FlatMapAll(ml, f) - def flatMapR[T](f: M#Map[Result] => Task[T]): Task[T] = new FlatMapped(ml, f) - def mapH[T](f: M#Map[Result]#Raw => T): Task[T] = new MapAll(ml, f) - def mapR[T](f: M#Map[Result] => T): Task[T] = new Mapped(ml, f) - def flatFailure[T](f: Seq[Incomplete] => Task[T]): Task[T] = new FlatMapFailure(ml, f) - def mapFailure[T](f: Seq[Incomplete] => T): Task[T] = new MapFailure(ml, f) + implicit def multInputTask[In <: HList](tasks: Tasks[In]): MultiInTask[In] = new MultiInTask[In] { + def flatMap[T](f: In => Task[T]): Task[T] = new FlatMapAll(tasks, f) + def flatMapR[T](f: Results[In] => Task[T]): Task[T] = new FlatMapped(tasks, f) + def mapH[T](f: In => T): Task[T] = new MapAll(tasks, f) + def mapR[T](f: Results[In] => T): Task[T] = new Mapped(tasks, f) + def flatFailure[T](f: Seq[Incomplete] => Task[T]): Task[T] = new FlatMapFailure(tasks, f) + def mapFailure[T](f: Seq[Incomplete] => T): Task[T] = new MapFailure(tasks, f) } implicit def singleInputTask[S](in: Task[S]): SingleInTask[S] = new SingleInTask[S] { - private val ml = in :^: MNil - private def headM = (_: ml.Map[Result]).head - private def headH = (_: S :+: HNil).head + type HL = S :+: HNil + private val ml = in :^: KNil + private def headM = (_: Results[HL]).combine.head + private def headH = (_: HL).head private def headS = (_: Seq[Incomplete]).head - def flatMapR[T](f: Result[S] => Task[T]): Task[T] = new FlatMapped[T, ml.type](ml, f ∙ headM) - def flatMap[T](f: S => Task[T]): Task[T] = new FlatMapAll[T, ml.type](ml, f ∙ headH) - def map[T](f: S => T): Task[T] = new MapAll[T, ml.type](ml, f ∙ headH) - def mapR[T](f: Result[S] => T): Task[T] = new Mapped[T, ml.type](ml, f ∙ headM) + def flatMapR[T](f: Result[S] => Task[T]): Task[T] = new FlatMapped[T, HL](ml, f ∙ headM) + def flatMap[T](f: S => Task[T]): Task[T] = new FlatMapAll(ml, f ∙ headH) + def map[T](f: S => T): Task[T] = new MapAll(ml, f ∙ headH) + def mapR[T](f: Result[S] => T): Task[T] = new Mapped[T, HL](ml, f ∙ headM) def flatFailure[T](f: Incomplete => Task[T]): Task[T] = new FlatMapFailure(ml, f ∙ headS) def mapFailure[T](f: Incomplete => T): Task[T] = new MapFailure(ml, f ∙ headS) def dependsOn(tasks: Task[_]*): Task[S] = new DependsOn(in, tasks) @@ -90,35 +94,35 @@ object Task implicit val taskToNode = new (Task ~> NodeT[Task]#Apply) { def apply[T](t: Task[T]): Node[Task, T] = t match { - case Pure(eval) => toNode[T, MNil](MNil, _ => Right(eval()) ) - case Mapped(in, f) => toNode[T, in.type](in, right ∙ f ) - case MapAll(in, f) => toNode[T, in.type](in, right ∙ (f compose allM) ) - case MapFailure(in, f) => toNode[T, in.type](in, right ∙ (f compose failuresM)) - case FlatMapped(in, f) => toNode[T, in.type](in, left ∙ f ) - case FlatMapAll(in, f) => toNode[T, in.type](in, left ∙ (f compose allM) ) - case FlatMapFailure(in, f) => toNode[T, in.type](in, left ∙ (f compose failuresM)) + case Pure(eval) => toNode[T, HNil](KNil, _ => Right(eval()) ) + case Mapped(in, f) => toNode(in, right ∙ f ) + case MapAll(in, f) => toNode[T, in.Raw](in, right ∙ (f compose allM) ) + case MapFailure(in, f) => toNode[T, in.Raw](in, right ∙ (f compose failuresM)) + case FlatMapped(in, f) => toNode(in, left ∙ f ) + case FlatMapAll(in, f) => toNode[T, in.Raw](in, left ∙ (f compose allM) ) + case FlatMapFailure(in, f) => toNode[T, in.Raw](in, left ∙ (f compose failuresM)) case DependsOn(in, tasks) => join[T, Any](tasks, (_: Seq[Result[_]]) => Left(in)) case j@ Join(in, f) => join[T, j.Uniform](in, f compose all) } } def join[T, D](tasks: Seq[Task[D]], f: Seq[Result[D]] => Either[Task[T], T]): Node[Task, T] = new Node[Task, T] { - type Mixed = MNil - val mixedIn = MNil + type Mixed = HNil + val mixedIn = KNil type Uniform = D val uniformIn = tasks - def work(mixed: MNil, uniform: Seq[Result[Uniform]]) = { + def work(mixed: Results[HNil], uniform: Seq[Result[Uniform]]) = { val inc = failures(uniform) if(inc.isEmpty) f(uniform) else throw Incomplete(causes = inc) } } - def toNode[T, In <: MList[Task]](in: In, f: In#Map[Result] => Either[Task[T], T]): Node[Task, T] = new Node[Task, T] { + def toNode[T, In <: HList](in: Tasks[In], f: Results[In] => Either[Task[T], T]): Node[Task, T] = new Node[Task, T] { type Mixed = In val mixedIn = in type Uniform = Nothing val uniformIn = Nil - def work(results: Mixed#Map[Result], units: Seq[Result[Uniform]]) = f(results) + def work(results: Results[In], units: Seq[Result[Uniform]]) = f(results) } - def allM[In <: MList[Result]]: In => In#Raw = in => + def allM[In <: HList]: Results[In] => In = in => { val incs = failuresM(in) if(incs.isEmpty) in.down(Result.tryValue) else throw Incomplete(causes = incs) @@ -128,7 +132,7 @@ object Task val incs = failures(in) if(incs.isEmpty) in.map(Result.tryValue.apply[D]) else throw Incomplete(causes = incs) } - def failuresM[In <: MList[Result]]: In => Seq[Incomplete] = x => failures[Any](x.toList) + def failuresM[In <: HList]: Results[In] => Seq[Incomplete] = x => failures[Any](x.toList) def failures[A]: Seq[Result[A]] => Seq[Incomplete] = _.collect { case Inc(i) => i } def run[T](root: Task[T], checkCycles: Boolean, maxWorkers: Int): Result[T] = @@ -155,5 +159,5 @@ object Task reducePair( reduce(a, f), reduce(b, f), f ) } def reducePair[S](a: Task[S], b: Task[S], f: (S, S) => S): Task[S] = - (a :^: b :^: MNil) mapH { case x :+: y :+: HNil => f(x,y) } + (a :^: b :^: KNil) mapH { case x :+: y :+: HNil => f(x,y) } } \ No newline at end of file diff --git a/tasks/src/test/scala/Test.scala b/tasks/src/test/scala/Test.scala index 71121a844..14cf59948 100644 --- a/tasks/src/test/scala/Test.scala +++ b/tasks/src/test/scala/Test.scala @@ -13,33 +13,35 @@ object Test val b = pure[Boolean](error("test")) val b2 = pure(true) val c = pure("asdf") - val i3 = a :^: b :^: c :^: MNil - val i32 = a :^: b2 :^: c :^: MNil + val i3 = a :^: b :^: c :^: KNil + val i32 = a :^: b2 :^: c :^: KNil val fh= (_: Int :+: Boolean :+: String :+: HNil) match { case aa :+: bb :+: cc :+: HNil => aa + " " + bb + " " + cc } val h1 = i3 mapH fh val h2 = i32 mapH fh - val f: i3.Map[Result] => Any = { - case Value(aa) :^: Value(bb) :^: Value(cc) :^: MNil => aa + " " + bb + " " + cc + type Values = Results[i3.Raw] + + val f: Values => Any = { + case Value(aa) :^: Value(bb) :^: Value(cc) :^: KNil => aa + " " + bb + " " + cc case x => val cs = x.toList.collect { case Inc(x) => x } // workaround for double definition bug throw Incomplete(causes = cs) } val d2 = i32 mapR f - val f2: i3.Map[Result] => Task[Any] = { - case Value(aa) :^: Value(bb) :^: Value(cc) :^: MNil => new Pure(() => aa + " " + bb + " " + cc) + val f2: Values => Task[Any] = { + case Value(aa) :^: Value(bb) :^: Value(cc) :^: KNil => new Pure(() => aa + " " + bb + " " + cc) case x => d3 } lazy val d = i3 flatMapR f2 - val f3: i3.Map[Result] => Task[Any] = { - case Value(aa) :^: Value(bb) :^: Value(cc) :^: MNil => new Pure(() => aa + " " + bb + " " + cc) + val f3: Values => Task[Any] = { + case Value(aa) :^: Value(bb) :^: Value(cc) :^: KNil => new Pure(() => aa + " " + bb + " " + cc) case x => d2 } lazy val d3= i3 flatMapR f3 - def d4(i: Int): Task[Int] = MNil flatMap { _ => val x = math.random; if(x < 0.01) pure(i); else d4(i+1) } + def d4(i: Int): Task[Int] = KNil flatMap { _ => val x = math.random; if(x < 0.01) pure(i); else d4(i+1) } def go() { diff --git a/tasks/src/test/scala/TestRunnerSort.scala b/tasks/src/test/scala/TestRunnerSort.scala index a96b79c8a..80a8c3cd2 100644 --- a/tasks/src/test/scala/TestRunnerSort.scala +++ b/tasks/src/test/scala/TestRunnerSort.scala @@ -41,7 +41,7 @@ object TaskRunnerSortTest extends Properties("TaskRunnerSort") pure(a) flatMap { a => val pivot = a(0) val (lt,gte) = a.view.drop(1).partition(_ < pivot) - sort(lt) :^: sort(gte) :^: MNil mapH { + sort(lt) :^: sort(gte) :^: KNil mapH { case l :+: g :+: HNil => l ++ List(pivot) ++ g } } diff --git a/util/collection/HList.scala b/util/collection/HList.scala index a1e595eeb..db2c9db85 100644 --- a/util/collection/HList.scala +++ b/util/collection/HList.scala @@ -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) } diff --git a/util/collection/KList.scala b/util/collection/KList.scala new file mode 100644 index 000000000..1a6e72554 --- /dev/null +++ b/util/collection/KList.scala @@ -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 +} diff --git a/util/collection/MList.scala b/util/collection/MList.scala deleted file mode 100644 index 7adfc1568..000000000 --- a/util/collection/MList.scala +++ /dev/null @@ -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) ) -} \ No newline at end of file diff --git a/util/collection/Relation.scala b/util/collection/Relation.scala index c60925aba..170c82a74 100644 --- a/util/collection/Relation.scala +++ b/util/collection/Relation.scala @@ -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 [", ", ", "]") } \ No newline at end of file diff --git a/util/collection/Types.scala b/util/collection/Types.scala index de6cf5aec..c5d484c51 100644 --- a/util/collection/Types.scala +++ b/util/collection/Types.scala @@ -5,7 +5,7 @@ package sbt object Types extends TypeFunctions { - val :^: = MCons + val :^: = KCons val :+: = HCons type :+:[H, T <: HList] = HCons[H,T] } diff --git a/util/collection/src/test/scala/MListTest.scala b/util/collection/src/test/scala/KListTest.scala similarity index 62% rename from util/collection/src/test/scala/MListTest.scala rename to util/collection/src/test/scala/KListTest.scala index ffb86b18e..210084fb1 100644 --- a/util/collection/src/test/scala/MListTest.scala +++ b/util/collection/src/test/scala/KListTest.scala @@ -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") } } diff --git a/util/collection/src/test/scala/PMapTest.scala b/util/collection/src/test/scala/PMapTest.scala index 1ea66daaa..091012f6e 100644 --- a/util/collection/src/test/scala/PMapTest.scala +++ b/util/collection/src/test/scala/PMapTest.scala @@ -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") } diff --git a/util/collection/src/test/scala/RelationTest.scala b/util/collection/src/test/scala/RelationTest.scala index d8a76bc17..e82bd861d 100644 --- a/util/collection/src/test/scala/RelationTest.scala +++ b/util/collection/src/test/scala/RelationTest.scala @@ -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 } \ No newline at end of file