mirror of https://github.com/sbt/sbt.git
Refactor AList to handle K[F[a]]
We do need to treat AList like a typeclass after all because sbt.std.Transform.uniform needs to traverse over a List, and we won't be able to magically connvert a List into a tuple.
This commit is contained in:
parent
7d33a5949e
commit
c86fc37ce1
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Reference in New Issue