summaryrefslogtreecommitdiff
path: root/core/src
diff options
context:
space:
mode:
authorLi Haoyi <haoyi.sg@gmail.com>2017-11-16 23:20:22 -0800
committerLi Haoyi <haoyi.sg@gmail.com>2017-11-16 23:20:22 -0800
commit5d03f4390f110d87ca4578259fb86405b7febab8 (patch)
tree04e455bf95157c2ca12b3cee3bd7c8be2acee2cf /core/src
parenteaba6c7ed4b1dc29c3b0d05be58f1bfd122f369d (diff)
downloadmill-5d03f4390f110d87ca4578259fb86405b7febab8.tar.gz
mill-5d03f4390f110d87ca4578259fb86405b7febab8.tar.bz2
mill-5d03f4390f110d87ca4578259fb86405b7febab8.zip
Flesh out a principled implementation of the cross-build monad
Diffstat (limited to 'core/src')
-rw-r--r--core/src/main/scala/mill/define/Cross.scala70
-rw-r--r--core/src/test/scala/mill/CrossTests.scala165
2 files changed, 137 insertions, 98 deletions
diff --git a/core/src/main/scala/mill/define/Cross.scala b/core/src/main/scala/mill/define/Cross.scala
index 1f457096..8f8c01e8 100644
--- a/core/src/main/scala/mill/define/Cross.scala
+++ b/core/src/main/scala/mill/define/Cross.scala
@@ -1,67 +1,15 @@
package mill.define
-sealed trait Cross[T]{
- def flatMap[V](f: T => Cross[V]): Cross[V] = new Cross.FlatMapping(this, f)
- def map[V](f: T => V): Cross[V] = new Cross.Mapping(this, f)
- def withFilter(f: T => Boolean): Cross[T] = new Cross.Filtering(this, f)
+case class Cross[T](items: List[(List[Any], T)]){
+ def flatMap[V](f: T => Cross[V]): Cross[V] = new Cross(
+ items.flatMap{
+ case (l, v) => f(v).items.map{case (l2, v2) => (l2 ::: l, v2)}
+ }
+ )
+ def map[V](f: T => V): Cross[V] = new Cross(items.map{case (l, v) => (l, f(v))})
+ def withFilter(f: T => Boolean): Cross[T] = new Cross(items.filter(t => f(t._2)))
}
object Cross{
- class Listing[T](val items: Seq[T]) extends Cross[T]
- class Mapping[T, V](val parent: Cross[T], val f: T => V) extends Cross[V]
- class FlatMapping[T, V](val parent: Cross[T], val f: T => Cross[V]) extends Cross[V]
- class Filtering[T](val parent: Cross[T], val f: T => Boolean) extends Cross[T]
-
- def apply[T](t: T*) = new Cross.Listing(t)
-
- def evaluate[T](c: Cross[T]): List[(List[Any], T)] = c match{
- case c: Listing[T] => c.items.map(i => List(i) -> i).toList
- case c: Mapping[_, T] => evaluate(c.parent).map{case (l, v) => (l, c.f(v))}
- case c: FlatMapping[_, T] =>
- evaluate(c.parent).flatMap{
- case (l, v) => evaluate(c.f(v)).map{case (l2, v2) => (l2 ::: l, v2)}
- }
- case c: Filtering[T] => evaluate(c.parent).filter(t => c.f(t._2))
- }
- def test() = {
- val example1 = evaluate(
- for(a <- Cross(1, 2, 3))
- yield a.toString
- )
- pprint.log(example1)
-
- val example2 = evaluate(
- for{
- a <- Cross(1, 2, 3)
- b <- Cross("A", "B", "C")
- } yield b * a
- )
- pprint.pprintln(example2)
-
- val example3 = evaluate(
- for{
- a <- Cross(1, 2, 3)
- b <- Cross("A", "B", "C")
- c <- Cross(true, false)
- } yield b * a + c
- )
- pprint.log(example3)
-
- val example4 = evaluate(
- for{
- a <- Cross(1, 2, 3)
- b <- Cross("A", "B", "C")
- if !(a == 2 && b == "B")
- } yield b * a
- )
- pprint.log(example4)
-
- val example5 = evaluate(
- for{
- (a, b) <- for(a <- Cross(1, 2, 3); b <- Cross("A", "B", "C")) yield (a, b)
- c <- Cross(true, false)
- } yield b * a + c
- )
- pprint.log(example5)
- }
+ def apply[T](t: T*) = new Cross(t.map(i => List(i) -> i).toList)
} \ No newline at end of file
diff --git a/core/src/test/scala/mill/CrossTests.scala b/core/src/test/scala/mill/CrossTests.scala
index d39072c5..76cde1e9 100644
--- a/core/src/test/scala/mill/CrossTests.scala
+++ b/core/src/test/scala/mill/CrossTests.scala
@@ -6,45 +6,136 @@ import utest._
object CrossTests extends TestSuite{
val tests = Tests{
- 'test - {
- Cross.test()
+
+ def assertEquals[T](value: Cross[T], value1: Cross[T]) = {
+ assert(value == value1)
}
-// def assertEquals[T](value: Cross[T], value1: Cross[T]) = {
-// assert(value == value1)
-// }
-// 'map - assertEquals(
-// for(a <- Cross(1, 2, 3)) yield a.toString,
-// Cross(1 -> "1", 2 -> "2", 3 -> "3")
-// )
-// 'flatMapFilter - assertEquals(
-// for{
-// a <- Cross(1, 2)
-// b <- Cross("A", "B")
-// if !(a == 2 && b == "B")
-// } yield b * a,
-// Cross(
-// (1 -> ("A" -> "A")),
-// (1 -> ("B" -> "B")),
-// (2 -> ("A" -> "AA"))
-// )
-// )
-// 'reuse - {
-// val matrix = for{
-// a <- Cross(1, 2)
-// b <- Cross("A", "B")
-// if !(a == 2 && b == "B")
-// } yield ()
-// assertEquals(
-// for((a, (b, _)) <- matrix)
-// yield b * a,
-// Cross(
-// (1 -> ("A" -> "A")),
-// (1 -> ("B" -> "B")),
-// (2 -> ("A" -> "AA"))
-// )
-// )
-// }
+ 'single - assertEquals(
+ for(a <- Cross(1, 2, 3)) yield a.toString,
+ Cross(List((List(1), "1"), (List(2), "2"), (List(3), "3")))
+ )
+
+
+
+ 'double - assertEquals(
+ for{
+ a <- Cross(1, 2, 3)
+ b <- Cross("A", "B", "C")
+ } yield b * a,
+ Cross(
+ List(
+ (List("A", 1), "A"),
+ (List("B", 1), "B"),
+ (List("C", 1), "C"),
+ (List("A", 2), "AA"),
+ (List("B", 2), "BB"),
+ (List("C", 2), "CC"),
+ (List("A", 3), "AAA"),
+ (List("B", 3), "BBB"),
+ (List("C", 3), "CCC")
+ )
+ )
+ )
+
+
+ 'triple - assertEquals(
+ for{
+ a <- Cross(1, 2)
+ b <- Cross("A", "B")
+ c <- Cross(true, false)
+ } yield b * a + c,
+ Cross(
+ List(
+ (List(true, "A", 1), "Atrue"),
+ (List(false, "A", 1), "Afalse"),
+ (List(true, "B", 1), "Btrue"),
+ (List(false, "B", 1), "Bfalse"),
+ (List(true, "A", 2), "AAtrue"),
+ (List(false, "A", 2), "AAfalse"),
+ (List(true, "B", 2), "BBtrue"),
+ (List(false, "B", 2), "BBfalse")
+ )
+ )
+ )
+
+
+ 'filter - assertEquals(
+ for{
+ a <- Cross(1, 2, 3)
+ b <- Cross("A", "B", "C")
+ if !(a == 2 && b == "B")
+ } yield b * a,
+ Cross(
+ List(
+ (List("A", 1), "A"),
+ (List("B", 1), "B"),
+ (List("C", 1), "C"),
+ (List("A", 2), "AA"),
+ (List("C", 2), "CC"),
+ (List("A", 3), "AAA"),
+ (List("B", 3), "BBB"),
+ (List("C", 3), "CCC")
+ )
+ )
+ )
+
+
+ 'middleFilter- assertEquals(
+ for{
+ a <- Cross(1, 2, 3)
+ if a != 2
+ b <- Cross("A", "B", "C")
+ } yield b * a,
+ Cross(
+ List(
+ (List("A", 1), "A"),
+ (List("B", 1), "B"),
+ (List("C", 1), "C"),
+ (List("A", 3), "AAA"),
+ (List("B", 3), "BBB"),
+ (List("C", 3), "CCC")
+ )
+ )
+ )
+
+
+ 'nestedComprehension1 - assertEquals(
+ for{
+ (a, b) <- for(a <- Cross(1, 2); b <- Cross("A", "B")) yield (a, b)
+ c <- Cross(true, false)
+ } yield b * a + c,
+ Cross(
+ List(
+ (List(true, "A", 1), "Atrue"),
+ (List(false, "A", 1), "Afalse"),
+ (List(true, "B", 1), "Btrue"),
+ (List(false, "B", 1), "Bfalse"),
+ (List(true, "A", 2), "AAtrue"),
+ (List(false, "A", 2), "AAfalse"),
+ (List(true, "B", 2), "BBtrue"),
+ (List(false, "B", 2), "BBfalse")
+ )
+ )
+ )
+ 'nestedComprehension2 - assertEquals(
+ for{
+ a <- Cross(1, 2)
+ (b, c) <- for(b <- Cross("A", "B"); c <- Cross(true, false)) yield (b, c)
+ } yield b * a + c,
+ Cross(
+ List(
+ (List(true, "A", 1), "Atrue"),
+ (List(false, "A", 1), "Afalse"),
+ (List(true, "B", 1), "Btrue"),
+ (List(false, "B", 1), "Bfalse"),
+ (List(true, "A", 2), "AAtrue"),
+ (List(false, "A", 2), "AAfalse"),
+ (List(true, "B", 2), "BBtrue"),
+ (List(false, "B", 2), "BBfalse")
+ )
+ )
+ )
}
}