diff options
author | Li Haoyi <haoyi.sg@gmail.com> | 2017-11-16 23:20:22 -0800 |
---|---|---|
committer | Li Haoyi <haoyi.sg@gmail.com> | 2017-11-16 23:20:22 -0800 |
commit | 5d03f4390f110d87ca4578259fb86405b7febab8 (patch) | |
tree | 04e455bf95157c2ca12b3cee3bd7c8be2acee2cf /core/src | |
parent | eaba6c7ed4b1dc29c3b0d05be58f1bfd122f369d (diff) | |
download | mill-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.scala | 70 | ||||
-rw-r--r-- | core/src/test/scala/mill/CrossTests.scala | 165 |
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") + ) + ) + ) } } |