mirror of https://github.com/sbt/sbt.git
Port Task Std
This commit is contained in:
parent
d4920a3b0c
commit
01d7f400d7
|
|
@ -190,6 +190,7 @@ lazy val sbtRoot: Project = (project in file("."))
|
|||
logicProj,
|
||||
utilCache,
|
||||
taskProj,
|
||||
stdTaskProj,
|
||||
)
|
||||
.settings(
|
||||
minimalSettings,
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import scala.reflect.TypeTest
|
|||
import scala.quoted.*
|
||||
import sbt.util.Applicative
|
||||
import sbt.util.Monad
|
||||
import Types.Id
|
||||
|
||||
/**
|
||||
* Implementation of a macro that provides a direct syntax for applicative functors and monads. It
|
||||
|
|
@ -197,11 +198,13 @@ trait Cont:
|
|||
case '[inputTypeTpe] =>
|
||||
'{
|
||||
given Applicative[F] = $instanceExpr
|
||||
AList.tuple.mapN[F, A1, inputTypeTpe & Tuple](${
|
||||
br.tupleExpr.asInstanceOf[Expr[Tuple.Map[inputTypeTpe & Tuple, F]]]
|
||||
})(
|
||||
${ lambda.asExprOf[inputTypeTpe => A1] }
|
||||
)
|
||||
AList
|
||||
.tuple[inputTypeTpe & Tuple]
|
||||
.mapN[F, A1](${
|
||||
br.tupleExpr.asInstanceOf[Expr[Tuple.Map[inputTypeTpe & Tuple, F]]]
|
||||
})(
|
||||
${ lambda.asExprOf[Tuple.Map[inputTypeTpe & Tuple, Id] => A1] }
|
||||
)
|
||||
}
|
||||
|
||||
eitherTree match
|
||||
|
|
|
|||
|
|
@ -1,132 +0,0 @@
|
|||
/*
|
||||
* sbt
|
||||
* Copyright 2011 - 2018, Lightbend, Inc.
|
||||
* Copyright 2008 - 2010, Mark Harrah
|
||||
* Licensed under Apache License 2.0 (see LICENSE)
|
||||
*/
|
||||
|
||||
package sbt
|
||||
|
||||
import sbt.internal.util.Types._
|
||||
import sbt.internal.util.{ ~>, AList, AttributeKey, AttributeMap }
|
||||
import ConcurrentRestrictions.{ Tag, TagMap, tagsKey }
|
||||
|
||||
// Action, Task, and Info are intentionally invariant in their type parameter.
|
||||
// Various natural transformations used, such as PMap, require invariant type constructors for correctness
|
||||
|
||||
/** Defines a task computation */
|
||||
sealed trait Action[T] {
|
||||
// TODO: remove after deprecated InputTask constructors are removed
|
||||
private[sbt] def mapTask(f: Task ~> Task): Action[T]
|
||||
}
|
||||
|
||||
/**
|
||||
* A direct computation of a value. If `inline` is true, `f` will be evaluated on the scheduler
|
||||
* thread without the overhead of normal scheduling when possible. This is intended as an
|
||||
* optimization for already evaluated values or very short pure computations.
|
||||
*/
|
||||
final case class Pure[T](f: () => T, `inline`: Boolean) extends Action[T] {
|
||||
private[sbt] def mapTask(f: Task ~> Task) = this
|
||||
}
|
||||
|
||||
/** Applies a function to the result of evaluating a heterogeneous list of other tasks. */
|
||||
final case class Mapped[T, K[L[x]]](in: K[Task], f: K[Result] => T, alist: AList[K])
|
||||
extends Action[T] {
|
||||
private[sbt] def mapTask(g: Task ~> Task) = Mapped[T, K](alist.transform(in, g), f, alist)
|
||||
}
|
||||
|
||||
/** Computes another task to evaluate based on results from evaluating other tasks. */
|
||||
final case class FlatMapped[T, K[L[x]]](in: K[Task], f: K[Result] => Task[T], alist: AList[K])
|
||||
extends Action[T] {
|
||||
private[sbt] def mapTask(g: Task ~> Task) =
|
||||
FlatMapped[T, K](alist.transform(in, g), g.fn[T] compose f, alist)
|
||||
}
|
||||
|
||||
/** A computation `in` that requires other tasks `deps` to be evaluated first. */
|
||||
final case class DependsOn[T](in: Task[T], deps: Seq[Task[_]]) extends Action[T] {
|
||||
private[sbt] def mapTask(g: Task ~> Task) = DependsOn[T](g(in), deps.map(t => g(t)))
|
||||
}
|
||||
|
||||
/**
|
||||
* A computation that operates on the results of a homogeneous list of other tasks. It can either
|
||||
* return another task to be evaluated or the final value.
|
||||
*/
|
||||
final case class Join[T, U](in: Seq[Task[U]], f: Seq[Result[U]] => Either[Task[T], T])
|
||||
extends Action[T] {
|
||||
private[sbt] def mapTask(g: Task ~> Task) =
|
||||
Join[T, U](in.map(g.fn[U]), sr => f(sr).left.map(g.fn[T]))
|
||||
}
|
||||
|
||||
/**
|
||||
* A computation that conditionally falls back to a second transformation. This can be used to
|
||||
* encode `if` conditions.
|
||||
*/
|
||||
final case class Selected[A, B](fab: Task[Either[A, B]], fin: Task[A => B]) extends Action[B] {
|
||||
private def ml = AList.single[Either[A, B]]
|
||||
type K[L[x]] = L[Either[A, B]]
|
||||
|
||||
private[sbt] def mapTask(g: Task ~> Task) =
|
||||
Selected[A, B](g(fab), g(fin))
|
||||
|
||||
/**
|
||||
* Encode this computation as a flatMap.
|
||||
*/
|
||||
private[sbt] def asFlatMapped: FlatMapped[B, K] = {
|
||||
val f: Either[A, B] => Task[B] = {
|
||||
case Right(b) => std.TaskExtra.task(b)
|
||||
case Left(a) => std.TaskExtra.singleInputTask(fin).map(_(a))
|
||||
}
|
||||
FlatMapped[B, K](
|
||||
fab, {
|
||||
f compose std.TaskExtra.successM
|
||||
},
|
||||
ml
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/** Combines metadata `info` and a computation `work` to define a task. */
|
||||
final case class Task[T](info: Info[T], work: Action[T]) {
|
||||
override def toString = info.name getOrElse ("Task(" + info + ")")
|
||||
override def hashCode = info.hashCode
|
||||
|
||||
def tag(tags: Tag*): Task[T] = tagw(tags.map(t => (t, 1)): _*)
|
||||
def tagw(tags: (Tag, Int)*): Task[T] = {
|
||||
val tgs: TagMap = info.get(tagsKey).getOrElse(TagMap.empty)
|
||||
val value = tags.foldLeft(tgs)((acc, tag) => acc + tag)
|
||||
val nextInfo = info.set(tagsKey, value)
|
||||
copy(info = nextInfo)
|
||||
}
|
||||
|
||||
def tags: TagMap = info get tagsKey getOrElse TagMap.empty
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to provide information about a task, such as the name, description, and tags for controlling
|
||||
* concurrent execution.
|
||||
* @param attributes
|
||||
* Arbitrary user-defined key/value pairs describing this task
|
||||
* @param post
|
||||
* a transformation that takes the result of evaluating this task and produces user-defined
|
||||
* key/value pairs.
|
||||
*/
|
||||
final case class Info[T](
|
||||
attributes: AttributeMap = AttributeMap.empty,
|
||||
post: T => AttributeMap = Info.defaultAttributeMap
|
||||
) {
|
||||
import Info._
|
||||
def name = attributes.get(Name)
|
||||
def description = attributes.get(Description)
|
||||
def setName(n: String) = set(Name, n)
|
||||
def setDescription(d: String) = set(Description, d)
|
||||
def set[A](key: AttributeKey[A], value: A) = copy(attributes = this.attributes.put(key, value))
|
||||
def get[A](key: AttributeKey[A]): Option[A] = attributes.get(key)
|
||||
def postTransform(f: (T, AttributeMap) => AttributeMap) = copy(post = (t: T) => f(t, post(t)))
|
||||
|
||||
override def toString = if (attributes.isEmpty) "_" else attributes.toString
|
||||
}
|
||||
object Info {
|
||||
val Name = AttributeKey[String]("name")
|
||||
val Description = AttributeKey[String]("description")
|
||||
val defaultAttributeMap = const(AttributeMap.empty)
|
||||
}
|
||||
|
|
@ -0,0 +1,59 @@
|
|||
/*
|
||||
* sbt
|
||||
* Copyright 2011 - 2018, Lightbend, Inc.
|
||||
* Copyright 2008 - 2010, Mark Harrah
|
||||
* Licensed under Apache License 2.0 (see LICENSE)
|
||||
*/
|
||||
|
||||
package sbt
|
||||
|
||||
import sbt.internal.util.Types._
|
||||
import sbt.internal.util.{ ~>, AList, AttributeKey, AttributeMap }
|
||||
import ConcurrentRestrictions.{ Tag, TagMap, tagsKey }
|
||||
import sbt.internal.Action
|
||||
|
||||
/** Combines metadata `info` and a computation `work` to define a task. */
|
||||
final case class Task[A](info: Info[A], work: Action[A]) {
|
||||
override def toString = info.name getOrElse ("Task(" + info + ")")
|
||||
override def hashCode = info.hashCode
|
||||
|
||||
def tag(tags: Tag*): Task[A] = tagw(tags.map(t => (t, 1)): _*)
|
||||
def tagw(tags: (Tag, Int)*): Task[A] = {
|
||||
val tgs: TagMap = info.get(tagsKey).getOrElse(TagMap.empty)
|
||||
val value = tags.foldLeft(tgs)((acc, tag) => acc + tag)
|
||||
val nextInfo = info.set(tagsKey, value)
|
||||
copy(info = nextInfo)
|
||||
}
|
||||
|
||||
def tags: TagMap = info get tagsKey getOrElse TagMap.empty
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to provide information about a task, such as the name, description, and tags for controlling
|
||||
* concurrent execution.
|
||||
* @param attributes
|
||||
* Arbitrary user-defined key/value pairs describing this task
|
||||
* @param post
|
||||
* a transformation that takes the result of evaluating this task and produces user-defined
|
||||
* key/value pairs.
|
||||
*/
|
||||
final case class Info[T](
|
||||
attributes: AttributeMap = AttributeMap.empty,
|
||||
post: T => AttributeMap = Info.defaultAttributeMap
|
||||
) {
|
||||
import Info._
|
||||
def name = attributes.get(Name)
|
||||
def description = attributes.get(Description)
|
||||
def setName(n: String) = set(Name, n)
|
||||
def setDescription(d: String) = set(Description, d)
|
||||
def set[A](key: AttributeKey[A], value: A) = copy(attributes = this.attributes.put(key, value))
|
||||
def get[A](key: AttributeKey[A]): Option[A] = attributes.get(key)
|
||||
def postTransform(f: (T, AttributeMap) => AttributeMap) = copy(post = (t: T) => f(t, post(t)))
|
||||
|
||||
override def toString = if (attributes.isEmpty) "_" else attributes.toString
|
||||
}
|
||||
object Info {
|
||||
val Name = AttributeKey[String]("name")
|
||||
val Description = AttributeKey[String]("description")
|
||||
val defaultAttributeMap = const(AttributeMap.empty)
|
||||
}
|
||||
|
|
@ -0,0 +1,83 @@
|
|||
/*
|
||||
* sbt
|
||||
* Copyright 2011 - 2018, Lightbend, Inc.
|
||||
* Copyright 2008 - 2010, Mark Harrah
|
||||
* Licensed under Apache License 2.0 (see LICENSE)
|
||||
*/
|
||||
|
||||
package sbt
|
||||
package internal
|
||||
|
||||
import sbt.internal.util.AList
|
||||
|
||||
// Action, Task, and Info are intentionally invariant in their type parameter.
|
||||
// Various natural transformations used, such as PMap, require invariant type constructors for correctness
|
||||
|
||||
/** Defines a task computation */
|
||||
enum Action[A]:
|
||||
// TODO: remove after deprecated InputTask constructors are removed
|
||||
// private[sbt] def mapTask(f: [A1] => Task[A1] => Task[A1]): Action[A]
|
||||
|
||||
/**
|
||||
* A direct computation of a value. If `inline` is true, `f` will be evaluated on the scheduler
|
||||
* thread without the overhead of normal scheduling when possible. This is intended as an
|
||||
* optimization for already evaluated values or very short pure computations.
|
||||
*/
|
||||
case Pure[A](f: () => A, `inline`: Boolean) extends Action[A]
|
||||
// private[sbt] def mapTask(f: [A1] => Task[A1] => Task[A1]) = this
|
||||
|
||||
/** Applies a function to the result of evaluating a heterogeneous list of other tasks. */
|
||||
case Mapped[A, K[F[_]]](in: K[Task], f: K[Result] => A, alist: AList[K]) extends Action[A]
|
||||
// private[sbt] def mapTask(g: Task ~> Task) = Mapped[A, K](alist.transform(in, g), f, alist)
|
||||
|
||||
/** Computes another task to evaluate based on results from evaluating other tasks. */
|
||||
case FlatMapped[A, K[F[_]]](
|
||||
in: K[Task],
|
||||
f: K[Result] => Task[A],
|
||||
alist: AList[K],
|
||||
) extends Action[A]
|
||||
// private[sbt] def mapTask(g: Task ~> Task) =
|
||||
// FlatMapped[A, K](alist.transform(in, g), g.fn[A] compose f, alist)
|
||||
|
||||
/** A computation `in` that requires other tasks `deps` to be evaluated first. */
|
||||
case DependsOn[A](in: Task[A], deps: Seq[Task[_]]) extends Action[A]
|
||||
// private[sbt] def mapTask(g: Task ~> Task) = DependsOn[A](g(in), deps.map(t => g(t)))
|
||||
|
||||
/**
|
||||
* A computation that operates on the results of a homogeneous list of other tasks. It can either
|
||||
* return another task to be evaluated or the final value.
|
||||
*/
|
||||
case Join[A, U](in: Seq[Task[U]], f: Seq[Result[U]] => Either[Task[A], A]) extends Action[A]
|
||||
// private[sbt] def mapTask(g: Task ~> Task) =
|
||||
// Join[A, U](in.map(g.fn[U]), sr => f(sr).left.map(g.fn[A]))
|
||||
|
||||
/**
|
||||
* A computation that conditionally falls back to a second transformation. This can be used to
|
||||
* encode `if` conditions.
|
||||
*/
|
||||
case Selected[A1, A2](fab: Task[Either[A1, A2]], fin: Task[A1 => A2]) extends Action[A2]
|
||||
|
||||
// private[sbt] def mapTask(g: Task ~> Task) =
|
||||
// Selected[A, B](g(fab), g(fin))
|
||||
|
||||
end Action
|
||||
|
||||
object Action:
|
||||
|
||||
/**
|
||||
* Encode this computation as a flatMap.
|
||||
*/
|
||||
private[sbt] def asFlatMapped[A1, A2](
|
||||
s: Action.Selected[A1, A2]
|
||||
): Action.FlatMapped[A2, [F[_]] =>> Tuple1[F[Either[A1, A2]]]] =
|
||||
val alist = AList.tuple[Tuple1[Either[A1, A2]]]
|
||||
val f: Either[A1, A2] => Task[A2] = {
|
||||
case Right(b) => std.TaskExtra.task(b)
|
||||
case Left(a) => std.TaskExtra.singleInputTask(s.fin).map(_(a))
|
||||
}
|
||||
Action.FlatMapped[A2, [F[_]] =>> Tuple1[F[Either[A1, A2]]]](
|
||||
Tuple1(s.fab),
|
||||
{ case Tuple1(r) => (f compose std.TaskExtra.successM)(r) },
|
||||
alist,
|
||||
)
|
||||
end Action
|
||||
|
|
@ -14,14 +14,15 @@ import sbt.internal.util.{ AList, AttributeMap }
|
|||
import sbt.internal.util.Types._
|
||||
import java.io.{ BufferedInputStream, BufferedReader, File, InputStream }
|
||||
import sbt.io.IO
|
||||
import sbt.internal.Action
|
||||
|
||||
sealed trait MultiInTask[K[L[x]]] {
|
||||
def flatMap[T](f: K[Id] => Task[T]): Task[T]
|
||||
def flatMapR[T](f: K[Result] => Task[T]): Task[T]
|
||||
def map[T](f: K[Id] => T): Task[T]
|
||||
def mapR[T](f: K[Result] => T): Task[T]
|
||||
def flatFailure[T](f: Seq[Incomplete] => Task[T]): Task[T]
|
||||
def mapFailure[T](f: Seq[Incomplete] => T): Task[T]
|
||||
sealed trait MultiInTask[K[F[_]]] {
|
||||
def flatMap[A](f: K[Id] => Task[A]): Task[A]
|
||||
def flatMapR[A](f: K[Result] => Task[A]): Task[A]
|
||||
def map[A](f: K[Id] => A): Task[A]
|
||||
def mapR[A](f: K[Result] => A): Task[A]
|
||||
def flatFailure[A](f: Seq[Incomplete] => Task[A]): Task[A]
|
||||
def mapFailure[A](f: Seq[Incomplete] => A): Task[A]
|
||||
}
|
||||
|
||||
sealed trait SingleInTask[S] {
|
||||
|
|
@ -99,7 +100,7 @@ trait TaskExtra0 {
|
|||
joinTasks0[Any](existToAny(in))
|
||||
private[sbt] def joinTasks0[S](in: Seq[Task[S]]): JoinTask[S, Seq] = new JoinTask[S, Seq] {
|
||||
def join: Task[Seq[S]] =
|
||||
Task[Seq[S]](Info(), new Join(in, (s: Seq[Result[S]]) => Right(TaskExtra.all(s))))
|
||||
Task[Seq[S]](Info(), Action.Join(in, (s: Seq[Result[S]]) => Right(TaskExtra.all(s))))
|
||||
def reduced(f: (S, S) => S): Task[S] = TaskExtra.reduced(in.toIndexedSeq, f)
|
||||
}
|
||||
private[sbt] def existToAny(in: Seq[Task[_]]): Seq[Task[Any]] = in.asInstanceOf[Seq[Task[Any]]]
|
||||
|
|
@ -109,9 +110,9 @@ trait TaskExtra extends TaskExtra0 {
|
|||
final def nop: Task[Unit] = constant(())
|
||||
final def constant[T](t: T): Task[T] = task(t)
|
||||
|
||||
final def task[T](f: => T): Task[T] = toTask(f _)
|
||||
final implicit def toTask[T](f: () => T): Task[T] = Task(Info(), new Pure(f, false))
|
||||
final def inlineTask[T](value: T): Task[T] = Task(Info(), new Pure(() => value, true))
|
||||
final def task[T](f: => T): Task[T] = toTask(() => f)
|
||||
final implicit def toTask[T](f: () => T): Task[T] = Task(Info(), Action.Pure(f, false))
|
||||
final def inlineTask[T](value: T): Task[T] = Task(Info(), Action.Pure(() => value, true))
|
||||
|
||||
final implicit def upcastTask[A >: B, B](t: Task[B]): Task[A] = t map { x =>
|
||||
x: A
|
||||
|
|
@ -126,61 +127,83 @@ trait TaskExtra extends TaskExtra0 {
|
|||
|
||||
final implicit def joinTasks[S](in: Seq[Task[S]]): JoinTask[S, Seq] = new JoinTask[S, Seq] {
|
||||
def join: Task[Seq[S]] =
|
||||
Task[Seq[S]](Info(), new Join(in, (s: Seq[Result[S]]) => Right(TaskExtra.all(s))))
|
||||
Task[Seq[S]](Info(), Action.Join(in, (s: Seq[Result[S]]) => Right(TaskExtra.all(s))))
|
||||
def reduced(f: (S, S) => S): Task[S] = TaskExtra.reduced(in.toIndexedSeq, f)
|
||||
}
|
||||
|
||||
final implicit def multT2Task[A, B](in: (Task[A], Task[B])) =
|
||||
multInputTask[λ[L[x] => (L[A], L[B])]](in)(AList.tuple2[A, B])
|
||||
final implicit def multT2Task[A1, A2](
|
||||
in: (Task[A1], Task[A2])
|
||||
): MultiInTask[[F[_]] =>> Tuple.Map[(A1, A2), F]] =
|
||||
given AList[[F[_]] =>> Tuple.Map[(A1, A2), F]] = AList.tuple[(A1, A2)]
|
||||
multInputTask[[F[_]] =>> Tuple.Map[(A1, A2), F]](in)
|
||||
|
||||
final implicit def multInputTask[K[L[X]]](tasks: K[Task])(implicit a: AList[K]): MultiInTask[K] =
|
||||
new MultiInTask[K] {
|
||||
def flatMapR[T](f: K[Result] => Task[T]): Task[T] =
|
||||
Task(Info(), new FlatMapped[T, K](tasks, f, a))
|
||||
def flatMap[T](f: K[Id] => Task[T]): Task[T] =
|
||||
Task(Info(), new FlatMapped[T, K](tasks, f compose allM, a))
|
||||
def flatFailure[T](f: Seq[Incomplete] => Task[T]): Task[T] =
|
||||
Task(Info(), new FlatMapped[T, K](tasks, f compose anyFailM, a))
|
||||
final implicit def multInputTask[K[F[_]]: AList](tasks: K[Task]): MultiInTask[K] =
|
||||
new MultiInTask[K]:
|
||||
override def flatMap[A](f: K[Id] => Task[A]): Task[A] =
|
||||
Task(Info(), Action.FlatMapped[A, K](tasks, f compose allM, AList[K]))
|
||||
override def flatMapR[A](f: K[Result] => Task[A]): Task[A] =
|
||||
Task(Info(), Action.FlatMapped[A, K](tasks, f, AList[K]))
|
||||
override def map[A](f: K[Id] => A): Task[A] =
|
||||
Task(Info(), Action.Mapped[A, K](tasks, f compose allM, AList[K]))
|
||||
override def mapR[A](f: K[Result] => A): Task[A] =
|
||||
Task(Info(), Action.Mapped[A, K](tasks, f, AList[K]))
|
||||
override def flatFailure[A](f: Seq[Incomplete] => Task[A]): Task[A] =
|
||||
Task(Info(), Action.FlatMapped[A, K](tasks, f compose anyFailM, AList[K]))
|
||||
override def mapFailure[A](f: Seq[Incomplete] => A): Task[A] =
|
||||
Task(Info(), Action.Mapped[A, K](tasks, f compose anyFailM, AList[K]))
|
||||
|
||||
def mapR[T](f: K[Result] => T): Task[T] = Task(Info(), new Mapped[T, K](tasks, f, a))
|
||||
def map[T](f: K[Id] => T): Task[T] = Task(Info(), new Mapped[T, K](tasks, f compose allM, a))
|
||||
def mapFailure[T](f: Seq[Incomplete] => T): Task[T] =
|
||||
Task(Info(), new Mapped[T, K](tasks, f compose anyFailM, a))
|
||||
}
|
||||
final implicit def singleInputTask[S](in: Task[S]): SingleInTask[S] =
|
||||
new SingleInTask[S]:
|
||||
// type K[L[x]] = L[S]
|
||||
given alist: AList[[F[_]] =>> Tuple.Map[Tuple1[S], F]] = AList.tuple[Tuple1[S]]
|
||||
|
||||
final implicit def singleInputTask[S](in: Task[S]): SingleInTask[S] = new SingleInTask[S] {
|
||||
type K[L[x]] = L[S]
|
||||
private def ml = AList.single[S]
|
||||
def failure: Task[Incomplete] = mapFailure(idFun)
|
||||
def result: Task[Result[S]] = mapR(idFun)
|
||||
|
||||
def failure: Task[Incomplete] = mapFailure(idFun)
|
||||
def result: Task[Result[S]] = mapR(idFun)
|
||||
private def newInfo[A]: Info[A] = TaskExtra.newInfo(in.info)
|
||||
|
||||
private def newInfo[A]: Info[A] = TaskExtra.newInfo(in.info)
|
||||
override def flatMapR[A](f: Result[S] => Task[A]): Task[A] =
|
||||
Task(
|
||||
newInfo,
|
||||
Action.FlatMapped[A, [F[_]] =>> Tuple.Map[Tuple1[S], F]](
|
||||
AList.toTuple(in),
|
||||
AList.fromTuple(f),
|
||||
alist,
|
||||
)
|
||||
)
|
||||
|
||||
def flatMapR[T](f: Result[S] => Task[T]): Task[T] =
|
||||
Task(newInfo, new FlatMapped[T, K](in, f, ml))
|
||||
def mapR[T](f: Result[S] => T): Task[T] = Task(newInfo, new Mapped[T, K](in, f, ml))
|
||||
def dependsOn(tasks: Task[_]*): Task[S] = Task(newInfo, new DependsOn(in, tasks))
|
||||
override def mapR[A](f: Result[S] => A): Task[A] =
|
||||
Task(
|
||||
newInfo,
|
||||
Action.Mapped[A, [F[_]] =>> Tuple.Map[Tuple1[S], F]](
|
||||
AList.toTuple(in),
|
||||
AList.fromTuple(f),
|
||||
alist,
|
||||
)
|
||||
)
|
||||
|
||||
def flatMap[T](f: S => Task[T]): Task[T] = flatMapR(f compose successM)
|
||||
def flatFailure[T](f: Incomplete => Task[T]): Task[T] = flatMapR(f compose failM)
|
||||
override def dependsOn(tasks: Task[_]*): Task[S] = Task(newInfo, Action.DependsOn(in, tasks))
|
||||
|
||||
def map[T](f: S => T): Task[T] = mapR(f compose successM)
|
||||
def mapFailure[T](f: Incomplete => T): Task[T] = mapR(f compose failM)
|
||||
override def flatMap[T](f: S => Task[T]): Task[T] = flatMapR(f compose successM)
|
||||
|
||||
def andFinally(fin: => Unit): Task[S] = mapR(x => Result.tryValue[S]({ fin; x }))
|
||||
def doFinally(t: Task[Unit]): Task[S] =
|
||||
flatMapR(x =>
|
||||
t.result.map { tx =>
|
||||
Result.tryValues[S](tx :: Nil, x)
|
||||
}
|
||||
)
|
||||
def ||[T >: S](alt: Task[T]): Task[T] = flatMapR {
|
||||
case Value(v) => task(v: T)
|
||||
case Inc(_) => alt
|
||||
}
|
||||
def &&[T](alt: Task[T]): Task[T] = flatMap(_ => alt)
|
||||
}
|
||||
override def flatFailure[T](f: Incomplete => Task[T]): Task[T] = flatMapR(f compose failM)
|
||||
|
||||
override def map[T](f: S => T): Task[T] = mapR(f compose successM)
|
||||
|
||||
override def mapFailure[T](f: Incomplete => T): Task[T] = mapR(f compose failM)
|
||||
|
||||
def andFinally(fin: => Unit): Task[S] = mapR(x => Result.tryValue[S]({ fin; x }))
|
||||
def doFinally(t: Task[Unit]): Task[S] =
|
||||
flatMapR(x =>
|
||||
t.result.map { tx =>
|
||||
Result.tryValues[S](tx :: Nil, x)
|
||||
}
|
||||
)
|
||||
def ||[T >: S](alt: Task[T]): Task[T] = flatMapR {
|
||||
case Result.Value(v) => task(v: T)
|
||||
case Result.Inc(_) => alt
|
||||
}
|
||||
def &&[T](alt: Task[T]): Task[T] = flatMap(_ => alt)
|
||||
|
||||
final implicit def toTaskInfo[S](in: Task[S]): TaskInfo[S] = new TaskInfo[S] {
|
||||
def describedAs(s: String): Task[S] = in.copy(info = in.info.setDescription(s))
|
||||
|
|
@ -263,35 +286,49 @@ object TaskExtra extends TaskExtra {
|
|||
reducePair(reduced(a, f), reduced(b, f), f)
|
||||
}
|
||||
|
||||
def reducePair[S](a: Task[S], b: Task[S], f: (S, S) => S): Task[S] =
|
||||
multInputTask[λ[L[x] => (L[S], L[S])]]((a, b))(AList.tuple2[S, S]) map f.tupled
|
||||
def reducePair[A1](a: Task[A1], b: Task[A1], f: (A1, A1) => A1): Task[A1] =
|
||||
given AList[[F[_]] =>> Tuple.Map[(A1, A1), F]] = AList.tuple[(A1, A1)]
|
||||
multInputTask[[F[_]] =>> Tuple.Map[(A1, A1), F]]((a, b)) map f.tupled
|
||||
|
||||
def anyFailM[K[L[x]]](implicit a: AList[K]): K[Result] => Seq[Incomplete] = in => {
|
||||
val incs = failuresM(a)(in)
|
||||
if (incs.isEmpty) expectedFailure else incs
|
||||
def anyFailM[K[F[_]]: AList]: K[Result] => Seq[Incomplete] = in => {
|
||||
val incs = failuresM[K](AList[K])(in)
|
||||
if incs.isEmpty then expectedFailure
|
||||
else incs
|
||||
}
|
||||
|
||||
def failM[A]: Result[A] => Incomplete = {
|
||||
case Result.Inc(i) => i
|
||||
case _ => expectedFailure
|
||||
}
|
||||
def failM[T]: Result[T] => Incomplete = { case Inc(i) => i; case _ => expectedFailure }
|
||||
|
||||
def expectedFailure = throw Incomplete(None, message = Some("Expected dependency to fail."))
|
||||
|
||||
def successM[T]: Result[T] => T = { case Inc(i) => throw i; case Value(t) => t }
|
||||
def allM[K[L[x]]](implicit a: AList[K]): K[Result] => K[Id] = in => {
|
||||
val incs = failuresM(a)(in)
|
||||
if (incs.isEmpty) a.transform(in, Result.tryValue) else throw incompleteDeps(incs)
|
||||
def successM[A]: Result[A] => A = {
|
||||
case Result.Inc(i) => throw i
|
||||
case Result.Value(a) => a
|
||||
}
|
||||
def failuresM[K[L[x]]](implicit a: AList[K]): K[Result] => Seq[Incomplete] =
|
||||
x => failures[Any](a.toList(x))
|
||||
|
||||
def allM[K[F[_]]: AList]: K[Result] => K[Id] = in => {
|
||||
val incs = failuresM[K](AList[K])(in)
|
||||
if incs.isEmpty then AList[K].transform[Result, Id](in)(Result.tryValue) // .asInstanceOf
|
||||
else throw incompleteDeps(incs)
|
||||
}
|
||||
def failuresM[K[F[_]]: AList]: K[Result] => Seq[Incomplete] = x =>
|
||||
failures[Any](AList[K].toList(x))
|
||||
|
||||
def all[D](in: Seq[Result[D]]): Seq[D] = {
|
||||
val incs = failures(in)
|
||||
if (incs.isEmpty) in.map(Result.tryValue.fn[D]) else throw incompleteDeps(incs)
|
||||
if incs.isEmpty then in.map(Result.tryValue[D])
|
||||
else throw incompleteDeps(incs)
|
||||
}
|
||||
def failures[A](results: Seq[Result[A]]): Seq[Incomplete] = results.collect {
|
||||
case Result.Inc(i) => i
|
||||
}
|
||||
def failures[A](results: Seq[Result[A]]): Seq[Incomplete] = results.collect { case Inc(i) => i }
|
||||
|
||||
def incompleteDeps(incs: Seq[Incomplete]): Incomplete = Incomplete(None, causes = incs)
|
||||
|
||||
def select[A, B](fab: Task[Either[A, B]], f: Task[A => B]): Task[B] =
|
||||
Task(newInfo(fab.info), new Selected[A, B](fab, f))
|
||||
Task(newInfo(fab.info), Action.Selected[A, B](fab, f))
|
||||
|
||||
// The "taskDefinitionKey" is used, at least, by the ".previous" functionality.
|
||||
// But apparently it *cannot* survive a task map/flatMap/etc. See actions/depends-on.
|
||||
|
|
|
|||
|
|
@ -8,24 +8,28 @@
|
|||
package sbt
|
||||
package std
|
||||
|
||||
import sbt.internal.Action
|
||||
import sbt.internal.util.Types._
|
||||
import sbt.internal.util.{ ~>, AList, DelegatingPMap, RMap }
|
||||
import TaskExtra.{ all, existToAny }
|
||||
import sbt.internal.util.Types.*
|
||||
|
||||
object Transform:
|
||||
def fromDummy[A](original: Task[A])(action: => A): Task[A] =
|
||||
Task(original.info, Action.Pure(() => action, false))
|
||||
|
||||
object Transform {
|
||||
def fromDummy[T](original: Task[T])(action: => T): Task[T] =
|
||||
Task(original.info, Pure(action _, false))
|
||||
def fromDummyStrict[T](original: Task[T], value: T): Task[T] = fromDummy(original)(value)
|
||||
|
||||
implicit def to_~>|[K[_], V[_]](map: RMap[K, V]): K ~>| V = new (K ~>| V) {
|
||||
def apply[T](k: K[T]): Option[V[T]] = map.get(k)
|
||||
}
|
||||
implicit def to_~>|[K[_], V[_]](map: RMap[K, V]): ~>|[K, V] =
|
||||
[A] => (k: K[A]) => map.get(k)
|
||||
|
||||
final case class DummyTaskMap(mappings: List[TaskAndValue[_]]) {
|
||||
def ::[T](tav: (Task[T], T)): DummyTaskMap =
|
||||
DummyTaskMap(new TaskAndValue(tav._1, tav._2) :: mappings)
|
||||
}
|
||||
|
||||
final class TaskAndValue[T](val task: Task[T], val value: T)
|
||||
|
||||
def dummyMap(dummyMap: DummyTaskMap): Task ~>| Task = {
|
||||
val pmap = new DelegatingPMap[Task, Task](new collection.mutable.ListMap)
|
||||
def add[T](dummy: TaskAndValue[T]): Unit = {
|
||||
|
|
@ -36,35 +40,43 @@ object Transform {
|
|||
}
|
||||
|
||||
/** Applies `map`, returning the result if defined or returning the input unchanged otherwise. */
|
||||
implicit def getOrId(map: Task ~>| Task): Task ~> Task =
|
||||
λ[Task ~> Task](in => map(in).getOrElse(in))
|
||||
implicit def getOrId(map: Task ~>| Task): [A] => Task[A] => Task[A] =
|
||||
[A] => (in: Task[A]) => map(in).getOrElse(in)
|
||||
|
||||
def apply(dummies: DummyTaskMap) = taskToNode(getOrId(dummyMap(dummies)))
|
||||
|
||||
def taskToNode(pre: Task ~> Task): NodeView[Task] = new NodeView[Task] {
|
||||
def apply[T](t: Task[T]): Node[Task, T] = pre(t).work match {
|
||||
case Pure(eval, _) => uniform(Nil)(_ => Right(eval()))
|
||||
case m: Mapped[t, k] => toNode[t, k](m.in)(right ∙ m.f)(m.alist)
|
||||
case m: FlatMapped[t, k] => toNode[t, k](m.in)(left ∙ m.f)(m.alist)
|
||||
case s: Selected[_, t] => val m = s.asFlatMapped; toNode(m.in)(left ∙ m.f)(m.alist)
|
||||
case DependsOn(in, deps) => uniform(existToAny(deps))(const(Left(in)) compose all)
|
||||
case Join(in, f) => uniform(in)(f)
|
||||
}
|
||||
def inline[T](t: Task[T]): Option[() => T] = t.work match {
|
||||
case Pure(eval, true) => Some(eval)
|
||||
case _ => None
|
||||
}
|
||||
}
|
||||
def taskToNode(pre: [A] => Task[A] => Task[A]): NodeView[Task] =
|
||||
new NodeView[Task]:
|
||||
import Action.*
|
||||
def apply[T](t: Task[T]): Node[Task, T] = pre(t).work match
|
||||
case Pure(eval, _) => uniform(Nil)(_ => Right(eval()))
|
||||
case m: Mapped[a, k] => toNode[a, k](m.in)(right[a] compose m.f)(m.alist)
|
||||
case m: FlatMapped[a, k] =>
|
||||
toNode[a, k](m.in)(left[Task[a]] compose m.f)(m.alist) // (m.alist)
|
||||
case s: Selected[a1, a2] =>
|
||||
val m = Action.asFlatMapped[a1, a2](s)
|
||||
toNode[a2, [F[_]] =>> Tuple1[F[Either[a1, a2]]]](m.in)(left[Task[a2]] compose m.f)(
|
||||
m.alist
|
||||
)
|
||||
case DependsOn(in, deps) => uniform(existToAny(deps))(const(Left(in)) compose all)
|
||||
case Join(in, f) => uniform(in)(f)
|
||||
|
||||
def uniform[T, D](tasks: Seq[Task[D]])(f: Seq[Result[D]] => Either[Task[T], T]): Node[Task, T] =
|
||||
toNode[T, λ[L[x] => List[L[D]]]](tasks.toList)(f)(AList.seq[D])
|
||||
def inline1[T](t: Task[T]): Option[() => T] = t.work match
|
||||
case Action.Pure(eval, true) => Some(eval)
|
||||
case _ => None
|
||||
|
||||
def toNode[T, k[L[x]]](
|
||||
inputs: k[Task]
|
||||
)(f: k[Result] => Either[Task[T], T])(implicit a: AList[k]): Node[Task, T] = new Node[Task, T] {
|
||||
type K[L[x]] = k[L]
|
||||
val in = inputs
|
||||
val alist = a
|
||||
def work(results: K[Result]) = f(results)
|
||||
}
|
||||
}
|
||||
def uniform[A1, D](tasks: Seq[Task[D]])(
|
||||
f: Seq[Result[D]] => Either[Task[A1], A1]
|
||||
): Node[Task, A1] =
|
||||
toNode[A1, [F[_]] =>> List[F[D]]](tasks.toList)(f)(AList.list[D])
|
||||
|
||||
def toNode[A1, K1[F[_]]: AList](
|
||||
inputs: K1[Task]
|
||||
)(f: K1[Result] => Either[Task[A1], A1]): Node[Task, A1] =
|
||||
new Node[Task, A1]:
|
||||
type K[F[_]] = K1[F]
|
||||
val in = inputs
|
||||
lazy val alist: AList[K] = AList[K]
|
||||
def work(results: K[Result]) = f(results)
|
||||
|
||||
end Transform
|
||||
|
|
|
|||
|
|
@ -30,14 +30,14 @@ object TaskGen extends std.TaskExtra {
|
|||
ExecuteProgress.empty[Task]
|
||||
)(std.Transform(dummies))
|
||||
try {
|
||||
x.run(root)(service)
|
||||
x.run(root)(service.asInstanceOf)
|
||||
} finally {
|
||||
shutdown()
|
||||
}
|
||||
}
|
||||
def tryRun[T](root: Task[T], checkCycles: Boolean, maxWorkers: Int): T =
|
||||
run(root, checkCycles, maxWorkers) match {
|
||||
case Value(v) => v
|
||||
case Inc(i) => throw i
|
||||
case Result.Value(v) => v
|
||||
case Result.Inc(i) => throw i
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -90,7 +90,7 @@ object TaskTest {
|
|||
ExecuteProgress.empty[Task]
|
||||
)(taskToNode(idK[Task]))
|
||||
try {
|
||||
x.run(root)(service)
|
||||
x.run(root)(service.asInstanceOf)
|
||||
} finally {
|
||||
shutdown()
|
||||
}
|
||||
|
|
@ -101,7 +101,7 @@ object TaskTest {
|
|||
restrictions: ConcurrentRestrictions[Task[_]]
|
||||
): T =
|
||||
run(root, checkCycles, restrictions) match {
|
||||
case Value(v) => v
|
||||
case Inc(i) => throw i
|
||||
case Result.Value(v) => v
|
||||
case Result.Inc(i) => throw i
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,11 +9,13 @@ package sbt
|
|||
|
||||
import sbt.internal.util.AList
|
||||
|
||||
object Test extends std.TaskExtra {
|
||||
def t2[A, B](a: Task[A], b: Task[B]) =
|
||||
multInputTask[λ[L[x] => (L[A], L[B])]]((a, b))(AList.tuple2)
|
||||
def t3[A, B, C](a: Task[A], b: Task[B], c: Task[C]) =
|
||||
multInputTask[λ[L[x] => (L[A], L[B], L[C])]]((a, b, c))(AList.tuple3)
|
||||
object Test extends std.TaskExtra:
|
||||
def t2[A1, A2](a1: Task[A1], a2: Task[A2]) =
|
||||
given AList[[F[_]] =>> Tuple.Map[(A1, A2), F]] = AList.tuple[(A1, A2)]
|
||||
multInputTask[[F[_]] =>> Tuple.Map[(A1, A2), F]]((a1, a2))
|
||||
def t3[A1, A2, A3](a1: Task[A1], a2: Task[A2], a3: Task[A3]) =
|
||||
given AList[[F[_]] =>> Tuple.Map[(A1, A2, A3), F]] = AList.tuple[(A1, A2, A3)]
|
||||
multInputTask[[F[_]] =>> Tuple.Map[(A1, A2, A3), F]]((a1, a2, a3))
|
||||
|
||||
val a = task(3)
|
||||
val b = task[Boolean](sys.error("test"))
|
||||
|
|
@ -26,22 +28,22 @@ object Test extends std.TaskExtra {
|
|||
type Values = (Result[Int], Result[Boolean], Result[String])
|
||||
|
||||
val f: Values => Any = {
|
||||
case (Value(aa), Value(bb), Value(cc)) => s"$aa $bb $cc"
|
||||
case (Result.Value(aa), Result.Value(bb), Result.Value(cc)) => s"$aa $bb $cc"
|
||||
case x =>
|
||||
val cs = x.productIterator.toList.collect { case Inc(x) =>
|
||||
val cs = x.productIterator.toList.collect { case Result.Inc(x) =>
|
||||
x
|
||||
} // workaround for double definition bug
|
||||
throw Incomplete(None, causes = cs)
|
||||
}
|
||||
val d2 = t3(a, b2, c) mapR f
|
||||
val f2: Values => Task[Any] = {
|
||||
case (Value(aa), Value(bb), Value(cc)) => task(s"$aa $bb $cc")
|
||||
case _ => d3
|
||||
case (Result.Value(aa), Result.Value(bb), Result.Value(cc)) => task(s"$aa $bb $cc")
|
||||
case _ => d3
|
||||
}
|
||||
lazy val d = t3(a, b, c) flatMapR f2
|
||||
val f3: Values => Task[Any] = {
|
||||
case (Value(aa), Value(bb), Value(cc)) => task(s"$aa $bb $cc")
|
||||
case _ => d2
|
||||
case (Result.Value(aa), Result.Value(bb), Result.Value(cc)) => task(s"$aa $bb $cc")
|
||||
case _ => d2
|
||||
}
|
||||
lazy val d3 = t3(a, b, c) flatMapR f3
|
||||
|
||||
|
|
@ -63,4 +65,4 @@ object Test extends std.TaskExtra {
|
|||
run(h1)
|
||||
run(h2)
|
||||
}
|
||||
}
|
||||
end Test
|
||||
|
|
|
|||
|
|
@ -44,17 +44,21 @@ object CompletionService {
|
|||
)
|
||||
(apply[A, T](pool), () => { pool.shutdownNow(); () })
|
||||
}
|
||||
|
||||
def apply[A, T](x: Executor): CompletionService[A, T] =
|
||||
apply(new ExecutorCompletionService[T](x))
|
||||
|
||||
def apply[A, T](completion: JCompletionService[T]): CompletionService[A, T] =
|
||||
new CompletionService[A, T] {
|
||||
def submit(node: A, work: () => T) = { CompletionService.submit(work, completion); () }
|
||||
def take() = completion.take().get()
|
||||
}
|
||||
|
||||
def submit[T](work: () => T, completion: JCompletionService[T]): () => T = {
|
||||
val future = submitFuture[T](work, completion)
|
||||
() => future.get
|
||||
}
|
||||
|
||||
private[sbt] def submitFuture[A](work: () => A, completion: JCompletionService[A]): JFuture[A] = {
|
||||
val future =
|
||||
try completion.submit {
|
||||
|
|
|
|||
|
|
@ -39,13 +39,16 @@ private[sbt] object Execute {
|
|||
final val checkPreAndPostConditions =
|
||||
sys.props.get("sbt.execute.extrachecks").exists(java.lang.Boolean.parseBoolean)
|
||||
}
|
||||
|
||||
sealed trait Completed {
|
||||
def process(): Unit
|
||||
}
|
||||
|
||||
private[sbt] trait NodeView[F[_]] {
|
||||
def apply[A](a: F[A]): Node[F, A]
|
||||
def inline1[A](a: F[A]): Option[() => A]
|
||||
}
|
||||
|
||||
final class Triggers[F[_]](
|
||||
val runBefore: collection.Map[F[Any], Seq[F[Any]]],
|
||||
val injectFor: collection.Map[F[Any], Seq[F[Any]]],
|
||||
|
|
@ -278,7 +281,7 @@ private[sbt] final class Execute[F[_] <: AnyRef](
|
|||
/** Send the work for this node to the provided Strategy. */
|
||||
def submit[A](node: F[A])(implicit strategy: Strategy): Unit = {
|
||||
val v = viewCache(node)
|
||||
val rs = AList.tuple.transform[F, Result, v.Tup](v.in)(getResult)
|
||||
val rs = v.alist.transform[F, Result](v.in)(getResult)
|
||||
// v.alist.transform(v.in)(getResult)
|
||||
strategy.submit(node.asInstanceOf, () => work(node, v.work(rs)))
|
||||
}
|
||||
|
|
@ -321,8 +324,7 @@ private[sbt] final class Execute[F[_] <: AnyRef](
|
|||
|
||||
def dependencies[A](node: F[A]): Iterable[F[Any]] = dependencies(viewCache(node.asInstanceOf))
|
||||
def dependencies[A](v: Node[F, A]): Iterable[F[Any]] =
|
||||
AList.tuple.toList[F, v.Tup](v.in).filter(dep => view.inline1(dep).isEmpty)
|
||||
// v.alist.toList(v.in).filter(dep => view.inline(dep).isEmpty)
|
||||
v.alist.toList[F](v.in).filter(dep => view.inline1(dep).isEmpty)
|
||||
|
||||
def runBefore[A](node: F[A]): Seq[F[A]] =
|
||||
getSeq[A](triggers.runBefore, node)
|
||||
|
|
|
|||
|
|
@ -7,6 +7,8 @@
|
|||
|
||||
package sbt
|
||||
|
||||
import sbt.internal.util.AList
|
||||
|
||||
/**
|
||||
* Represents a task node in a format understood by the task evaluation engine Execute.
|
||||
*
|
||||
|
|
@ -15,10 +17,11 @@ package sbt
|
|||
* @tparam A
|
||||
* the type computed by this node
|
||||
*/
|
||||
trait Node[Effect[_], A] {
|
||||
type Tup <: Tuple
|
||||
def in: Tuple.Map[Tup, Effect]
|
||||
private[sbt] trait Node[Effect[_], A]:
|
||||
type K[L[x]]
|
||||
def in: K[Effect]
|
||||
def alist: AList[K]
|
||||
|
||||
/** Computes the result of this task given the results from the inputs. */
|
||||
def work(inputs: Tuple.Map[Tup, Result]): Either[Effect[A], A]
|
||||
}
|
||||
def work(inputs: K[Result]): Either[Effect[A], A]
|
||||
end Node
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ import sbt.util.Applicative
|
|||
import Types._
|
||||
|
||||
/**
|
||||
* Arity-generic List. An abstraction over structured Tuple type constructor `X1[f[a]]`.
|
||||
* Arity-generic List. An abstraction over structured Tuple/List type constructor `X1[f[a]]`.
|
||||
*/
|
||||
trait AList[K[F[_]]]:
|
||||
import AList.idPoly
|
||||
|
|
@ -42,6 +42,8 @@ trait AList[K[F[_]]]:
|
|||
end AList
|
||||
|
||||
object AList:
|
||||
inline def apply[K[F[_]]: AList]: AList[K] = summon[AList[K]]
|
||||
|
||||
type Tail[X <: Tuple] <: Tuple = X match
|
||||
case _ *: xs => xs
|
||||
|
||||
|
|
|
|||
|
|
@ -19,11 +19,11 @@ trait TypeFunctions:
|
|||
sealed trait Compose[A[_], B[_]] { type Apply[T] = A[B[T]] }
|
||||
|
||||
sealed trait ∙[A[_], B[_]] { type l[T] = A[B[T]] }
|
||||
private type AnyLeft[T] = Left[T, Nothing]
|
||||
private type AnyRight[T] = Right[Nothing, T]
|
||||
final val left: [A] => A => Left[A, Nothing] = [A] => (a: A) => Left(a)
|
||||
private type AnyLeft[A] = Left[A, Nothing]
|
||||
private type AnyRight[A] = Right[Nothing, A]
|
||||
final val left: [A] => A => AnyLeft[A] = [A] => (a: A) => Left(a)
|
||||
|
||||
final val right: [A] => A => Right[Nothing, A] = [A] => (a: A) => Right(a)
|
||||
final val right: [A] => A => AnyRight[A] = [A] => (a: A) => Right(a)
|
||||
|
||||
final val some: [A] => A => Some[A] = [A] => (a: A) => Some(a)
|
||||
// Id ~> Left[*, Nothing] =
|
||||
|
|
@ -34,9 +34,10 @@ 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")
|
||||
|
||||
final def idK[F[_]]: [a] => F[a] => F[a] = [a] =>
|
||||
(fa: F[a]) => fa // .setToString("TypeFunctions.idK")
|
||||
/*
|
||||
def nestCon[M[_], N[_], G[_]](f: M ~> N): (M ∙ G)#l ~> (N ∙ G)#l =
|
||||
f.asInstanceOf[(M ∙ G)#l ~> (N ∙ G)#l] // implemented with a cast to avoid extra object+method call.
|
||||
// castless version:
|
||||
|
|
@ -47,6 +48,10 @@ trait TypeFunctions:
|
|||
*/
|
||||
type ~>|[F1[_], F2[_]] = [A] => F1[A] => Option[F2[A]]
|
||||
|
||||
extension (f: [a] => a => AnyRight[a])
|
||||
def compose[F3[_]](g: [a] => F3[a] => a): [a] => F3[a] => AnyRight[a] =
|
||||
[a] => (f3: F3[a]) => f(g(f3))
|
||||
|
||||
end TypeFunctions
|
||||
|
||||
/*
|
||||
|
|
|
|||
Loading…
Reference in New Issue