diff --git a/util-collection/src/main/scala/sbt/internal/util/AList.scala b/util-collection/src/main/scala/sbt/internal/util/AList.scala index 12d0cd9bc..d72b6dd36 100644 --- a/util-collection/src/main/scala/sbt/internal/util/AList.scala +++ b/util-collection/src/main/scala/sbt/internal/util/AList.scala @@ -14,31 +14,31 @@ import Types._ /** * Arity-generic List. An abstraction over structured Tuple type constructor `X1[f[a]]`. */ -trait AList: +trait AList[K[F[_]]]: import AList.idPoly - def transform[F1[_], F2[_], Tup <: Tuple](value: Tuple.Map[Tup, F1])( + def transform[F1[_], F2[_]](value: K[F1])( f: [a] => F1[a] => F2[a] - ): Tuple.Map[Tup, F2] + ): K[F2] - def traverse[F1[_], F2[_]: Applicative, Tup <: Tuple](value: Tuple.Map[Tup, F1])( + def traverse[F1[_], F2[_]: Applicative](value: K[F1])( f: [a] => F1[a] => F2[a] - ): F2[Tup] + ): F2[K[Id]] - def mapN[F1[_]: Applicative, A, Tup <: Tuple](value: Tuple.Map[Tup, F1])(f: Tup => A): F1[A] = - summon[Applicative[F1]].map(traverse[F1, F1, Tup](value)(idPoly[F1]))(f) + def mapN[F1[_]: Applicative, A1](value: K[F1])(f: K[Id] => A1): F1[A1] = + summon[Applicative[F1]].map(traverse[F1, F1](value)(idPoly[F1]))(f) - def traverseX[F1[_], F2[_]: Applicative, P[_], Tup <: Tuple](value: Tuple.Map[Tup, F1])( + def traverseX[F1[_], F2[_]: Applicative, P[_]](value: K[F1])( f: [a] => F1[a] => F2[P[a]] - ): F2[Tuple.Map[Tup, P]] + ): F2[K[P]] - def foldr[F1[_], A, Tup <: Tuple](value: Tuple.Map[Tup, F1], init: A)( - f: [a] => (F1[a], A) => A - ): A + def foldr[F1[_], A1](value: K[F1], init: A1)( + f: [a] => (F1[a], A1) => A1 + ): A1 - def toList[F1[_], Tup <: Tuple](value: Tuple.Map[Tup, F1]): List[F1[Any]] = + def toList[F1[_]](value: K[F1]): List[F1[Any]] = val f = [a] => (p1: F1[a], p2: List[F1[Any]]) => p1.asInstanceOf[F1[Any]] :: p2 - foldr[F1, List[F1[Any]], Tup](value, Nil)(f) + foldr[F1, List[F1[Any]]](value, Nil)(f) end AList object AList: @@ -49,46 +49,54 @@ object AList: def nil[Tup <: Tuple] = EmptyTuple.asInstanceOf[Tup] - lazy val tuple: AList = new AList: - override def transform[F1[_], F2[_], Tup <: Tuple](value: Tuple.Map[Tup, F1])( - f: [x] => F1[x] => F2[x] - ): Tuple.Map[Tup, F2] = - value match - case _: Tuple.Map[EmptyTuple, F1] => nil[Tuple.Map[Tup, F2]] - case (head: F1[x] @unchecked) *: tail => - (f(head) *: transform[F1, F2, Tail[Tup]](tail.asInstanceOf)(f)) - .asInstanceOf[Tuple.Map[Tup, F2]] + inline def toTuple[A](a: A): Tuple1[A] = Tuple1(a) - override def traverse[F1[_], F2[_]: Applicative, Tup <: Tuple](value: Tuple.Map[Tup, F1])( - f: [a] => F1[a] => F2[a] - ): F2[Tup] = - val F2 = summon[Applicative[F2]] - value match - case _: Tuple.Map[EmptyTuple, F1] => F2.pure(nil[Tup]) - case (head: F1[x] @unchecked) *: (tail: Tuple.Map[Tail[Tup], F1] @unchecked) => - val tt = traverse[F1, F2, Tail[Tup]](tail)(f) - val g = (t: Tail[Tup]) => (h: x) => (h *: t).asInstanceOf[Tup] - F2.ap[x, Tup](F2.map(tt)(g))(f(head)) + inline def fromTuple[A1, A2](f: A1 => A2): Tuple1[A1] => A2 = { case Tuple1(a) => f(a) } - override def traverseX[F1[_], F2[_]: Applicative, P[_], Tup <: Tuple]( - value: Tuple.Map[Tup, F1] - )( - f: [a] => F1[a] => F2[P[a]] - ): F2[Tuple.Map[Tup, P]] = - val F2 = summon[Applicative[F2]] - value match - case _: Tuple.Map[EmptyTuple, F1] => F2.pure(nil[Tuple.Map[Tup, P]]) - case (head: F1[x] @unchecked) *: (tail: Tuple.Map[Tail[Tup], F1] @unchecked) => - val tt = traverseX[F1, F2, P, Tail[Tup]](tail)(f) - val g = (t: Tuple.Map[Tail[Tup], P]) => - (h: P[x]) => (h *: t).asInstanceOf[Tuple.Map[Tup, P]] - F2.ap[P[x], Tuple.Map[Tup, P]](F2.map(tt)(g))(f(head)) + // givens for tuple map + given [Tup <: Tuple]: AList[[F[_]] =>> Tuple.Map[Tup, F]] = tuple[Tup] - override def foldr[F1[_], A, Tup <: Tuple](value: Tuple.Map[Tup, F1], init: A)( - f: [a] => (F1[a], A) => A - ): A = - value match - case _: Tuple.Map[EmptyTuple, F1] => init - case (head: F1[x] @unchecked) *: tail => - f(head, foldr[F1, A, Tail[Tup]](tail.asInstanceOf[Tuple.Map[Tail[Tup], F1]], init)(f)) + def tuple[Tup <: Tuple]: AList[[F[_]] =>> Tuple.Map[Tup, F]] = + new AList[[F[_]] =>> Tuple.Map[Tup, F]]: + override def transform[F1[_], F2[_]](value: Tuple.Map[Tup, F1])( + f: [x] => F1[x] => F2[x] + ): Tuple.Map[Tup, F2] = + value match + case _: Tuple.Map[EmptyTuple, F1] => nil[Tuple.Map[Tup, F2]] + case (head: F1[x] @unchecked) *: tail => + (f(head) *: transform[F1, F2](tail.asInstanceOf)(f)) + .asInstanceOf[Tuple.Map[Tup, F2]] + + override def traverse[F1[_], F2[_]: Applicative](value: Tuple.Map[Tup, F1])( + f: [a] => F1[a] => F2[a] + ): F2[Tuple.Map[Tup, Id]] = + val F2 = summon[Applicative[F2]] + value match + case _: Tuple.Map[EmptyTuple, F1] => F2.pure(nil[Tup].asInstanceOf[Tuple.Map[Tup, Id]]) + case (head: F1[x] @unchecked) *: (tail: Tuple.Map[Tail[Tup], F1] @unchecked) => + val tt = tuple[Tail[Tup]].traverse[F1, F2](tail)(f) + val g = (t: Tail[Tup]) => (h: x) => (h *: t) + F2.ap[x, Tup](F2.map(tt)(g.asInstanceOf))(f(head)).asInstanceOf[F2[Tuple.Map[Tup, Id]]] + + override def traverseX[F1[_], F2[_]: Applicative, P[_]]( + value: Tuple.Map[Tup, F1] + )( + f: [a] => F1[a] => F2[P[a]] + ): F2[Tuple.Map[Tup, P]] = + val F2 = summon[Applicative[F2]] + value match + case _: Tuple.Map[EmptyTuple, F1] => F2.pure(nil[Tuple.Map[Tup, P]]) + case (head: F1[x] @unchecked) *: (tail: Tuple.Map[Tail[Tup], F1] @unchecked) => + val tt = traverseX[F1, F2, P](tail.asInstanceOf)(f) + val g = (t: Tuple.Map[Tail[Tup], P]) => + (h: P[x]) => (h *: t).asInstanceOf[Tuple.Map[Tup, P]] + F2.ap[P[x], Tuple.Map[Tup, P]](F2.map(tt)(g.asInstanceOf))(f(head)) + + override def foldr[F1[_], A1](value: Tuple.Map[Tup, F1], init: A1)( + f: [a] => (F1[a], A1) => A1 + ): A1 = + value match + case _: Tuple.Map[EmptyTuple, F1] => init + case (head: F1[x] @unchecked) *: tail => + f(head, foldr[F1, A1](tail.asInstanceOf, init)(f)) end AList diff --git a/util-collection/src/main/scala/sbt/internal/util/TypeFunctions.scala b/util-collection/src/main/scala/sbt/internal/util/TypeFunctions.scala index accf313ff..aee296e51 100644 --- a/util-collection/src/main/scala/sbt/internal/util/TypeFunctions.scala +++ b/util-collection/src/main/scala/sbt/internal/util/TypeFunctions.scala @@ -34,7 +34,7 @@ trait TypeFunctions: final def idFun[A]: A => A = ((a: A) => a) // .setToString("TypeFunctions.id") final def const[A, B](b: B): A => B = ((_: A) => b) // .setToString(s"TypeFunctions.const($b)") -/* + /* final def idK[M[_]]: M ~> M = λ[M ~> M](m => m).setToString("TypeFunctions.idK") def nestCon[M[_], N[_], G[_]](f: M ~> N): (M ∙ G)#l ~> (N ∙ G)#l = @@ -44,7 +44,8 @@ trait TypeFunctions: type Endo[T] = T => T type ~>|[A[_], B[_]] = A ~> Compose[Option, B]#Apply - */ + */ + type ~>|[F1[_], F2[_]] = [A] => F1[A] => Option[F2[A]] end TypeFunctions diff --git a/util-collection/src/test/scala/AListTest.scala b/util-collection/src/test/scala/AListTest.scala index f51391d92..a5358938e 100644 --- a/util-collection/src/test/scala/AListTest.scala +++ b/util-collection/src/test/scala/AListTest.scala @@ -9,7 +9,7 @@ object AListTest extends BasicTestSuite: import sbt.internal.util.AList val tuple = t1 val f = (arg: (Int, String)) => arg._1.toString + "|" + arg._2 - val actual = AList.tuple.mapN[Option, String, (Int, String)](tuple)(f) + val actual = AList.tuple[(Int, String)].mapN[Option, String](tuple)(f) assert(actual == Option("1|foo")) } end AListTest