mirror of https://github.com/sbt/sbt.git
Merge pull request #7714 from adpi2/2.x-fix-7711
[2.x] Reduce heap size after load
This commit is contained in:
commit
d4e2f91008
|
|
@ -308,10 +308,11 @@ trait Cont:
|
|||
tupleMapRepr.asType match
|
||||
case '[tupleMap] =>
|
||||
'{
|
||||
given Applicative[F] = $applicativeExpr
|
||||
import TupleMapExtension.*
|
||||
${ br.tupleExpr.asInstanceOf[Expr[Tuple.Map[inputTypeTpe & Tuple, F]]] }
|
||||
.mapN(${ lambda.asExprOf[inputTypeTpe & Tuple => A1] })
|
||||
$applicativeExpr.mapN(
|
||||
${ br.tupleExpr.asInstanceOf[Expr[Tuple.Map[inputTypeTpe & Tuple, F]]] }
|
||||
)(
|
||||
${ lambda.asExprOf[inputTypeTpe & Tuple => A1] }
|
||||
)
|
||||
}
|
||||
eitherTree match
|
||||
case Left(_) =>
|
||||
|
|
|
|||
|
|
@ -242,7 +242,7 @@ object Def extends BuildSyntax with Init[Scope] with InitializeImplicits:
|
|||
sbt.internal.util.complete.Parsers.spaceDelimited(argLabel)
|
||||
|
||||
/** Lifts the result of a setting initialization into a Task. */
|
||||
def toITask[A1](i: Initialize[A1]): Initialize[Task[A1]] = map(i)(std.TaskExtra.inlineTask)
|
||||
def toITask[A1](i: Initialize[A1]): Initialize[Task[A1]] = i(std.TaskExtra.inlineTask)
|
||||
|
||||
inline def toSParser[A1](p: Parser[A1]): State => Parser[A1] = const(p)
|
||||
def toISParser[A1](p: Initialize[Parser[A1]]): Initialize[State => Parser[A1]] =
|
||||
|
|
|
|||
|
|
@ -347,14 +347,10 @@ object Scoped:
|
|||
protected def onTask[A2](f: Task[A1] => Task[A2]): Initialize[Task[A2]] =
|
||||
init.apply(f)
|
||||
|
||||
def flatMapTaskValue[T](f: A1 => Task[T]): Initialize[Task[T]] =
|
||||
onTask(_.result flatMap (f compose successM))
|
||||
def map[A2](f: A1 => A2): Initialize[Task[A2]] =
|
||||
onTask(_.result map (f compose successM))
|
||||
def andFinally(fin: => Unit): Initialize[Task[A1]] =
|
||||
onTask(_ andFinally fin)
|
||||
def doFinally(t: Task[Unit]): Initialize[Task[A1]] =
|
||||
onTask(_ doFinally t)
|
||||
def flatMapTaskValue[T](f: A1 => Task[T]): Initialize[Task[T]] = onTask(_.flatMap(f))
|
||||
def map[A2](f: A1 => A2): Initialize[Task[A2]] = onTask(_.map(f))
|
||||
def andFinally(fin: => Unit): Initialize[Task[A1]] = onTask(_.andFinally(fin))
|
||||
def doFinally(t: Task[Unit]): Initialize[Task[A1]] = onTask(_.doFinally(t))
|
||||
def ||[T >: A1](alt: Task[T]): Initialize[Task[T]] = onTask(_ || alt)
|
||||
def &&[T](alt: Task[T]): Initialize[Task[T]] = onTask(_ && alt)
|
||||
def tag(tags: Tag*): Initialize[Task[A1]] = onTask(_.tag(tags: _*))
|
||||
|
|
@ -842,4 +838,4 @@ class TupleWrap[Tup <: Tuple](value: Tuple.Map[Tup, Taskable]):
|
|||
type InitTask[A2] = Initialize[Task[A2]]
|
||||
lazy val initTasks = value.transform[InitTask]([a] => (t: Taskable[a]) => t.toTask)
|
||||
def mapN[A1](f: Tup => A1): Def.Initialize[Task[A1]] =
|
||||
initTasks.mapN[A1](f)(using std.FullInstance.initializeTaskMonad)
|
||||
std.FullInstance.initializeTaskMonad.mapN(initTasks)(f)
|
||||
|
|
|
|||
|
|
@ -18,7 +18,9 @@ object InitializeInstance:
|
|||
type F[x] = Initialize[x]
|
||||
|
||||
override def pure[A1](a: () => A1): Initialize[A1] = Def.pure(a)
|
||||
override def map[A1, A2](in: Initialize[A1])(f: A1 => A2): Initialize[A2] = Def.map(in)(f)
|
||||
override def map[A1, A2](in: Initialize[A1])(f: A1 => A2): Initialize[A2] = in(f)
|
||||
override def mapN[A1 <: Tuple, A2](t: Tuple.Map[A1, Initialize])(f: A1 => A2): Initialize[A2] =
|
||||
Def.app(t)(f)
|
||||
override def ap[A1, A2](ff: Initialize[A1 => A2])(fa: Initialize[A1]): Initialize[A2] =
|
||||
Def.ap[A1, A2](ff)(fa)
|
||||
override def flatMap[A1, A2](fa: Initialize[A1])(f: A1 => Initialize[A2]) =
|
||||
|
|
@ -63,6 +65,10 @@ object FullInstance:
|
|||
override def map[A1, A2](fa: Initialize[Task[A1]])(f: A1 => A2): Initialize[Task[A2]] =
|
||||
F1F2.map(fa)(f)
|
||||
|
||||
override def mapN[A1 <: Tuple, A2](t: Tuple.Map[A1, [a] =>> Initialize[Task[a]]])(
|
||||
f: A1 => A2
|
||||
): Initialize[Task[A2]] = F1F2.mapN(t)(f)
|
||||
|
||||
override def ap[A1, A2](ff: Initialize[Task[A1 => A2]])(
|
||||
fa: Initialize[Task[A1]]
|
||||
): Initialize[Task[A2]] =
|
||||
|
|
|
|||
|
|
@ -50,6 +50,7 @@ object Task:
|
|||
}
|
||||
|
||||
override def map[A1, A2](in: Task[A1])(f: A1 => A2): Task[A2] = in.map(f)
|
||||
override def mapN[A1 <: Tuple, A2](t: Tuple.Map[A1, Task])(f: A1 => A2): Task[A2] = t.mapN(f)
|
||||
override def flatMap[A1, A2](in: F[A1])(f: A1 => F[A2]): F[A2] = in.flatMap(f)
|
||||
override def flatten[A1](in: Task[Task[A1]]): Task[A1] = in.flatMap(identity)
|
||||
end Task
|
||||
|
|
|
|||
|
|
@ -313,8 +313,7 @@ object TaskExtra extends TaskExtra {
|
|||
if incs.isEmpty then in.unmap(Result.tryValue)
|
||||
else throw incompleteDeps(incs)
|
||||
}
|
||||
def failuresM[Tup <: Tuple]: Tuple.Map[Tup, Result] => Seq[Incomplete] = x =>
|
||||
failures(x.iterator.toList)
|
||||
def failuresM[Tup <: Tuple]: Tuple.Map[Tup, Result] => Seq[Incomplete] = x => failures(x.toList0)
|
||||
|
||||
def all[D](in: Seq[Result[D]]): Seq[D] = {
|
||||
val incs = failures(in)
|
||||
|
|
|
|||
|
|
@ -74,7 +74,7 @@ object Transform:
|
|||
)(f: Tuple.Map[Tup, Result] => Either[Task[A1], A1]): Node[A1] =
|
||||
new Node[A1]:
|
||||
type Inputs = Tuple.Map[Tup, Result]
|
||||
def dependencies: List[TaskId[?]] = deps.iterator.toList
|
||||
def dependencies: List[TaskId[?]] = deps.toList0
|
||||
def computeInputs(f: [a] => TaskId[a] => Result[a]) = deps.transform(f)
|
||||
def work(inputs: Inputs) = f(inputs)
|
||||
|
||||
|
|
|
|||
|
|
@ -221,7 +221,7 @@ abstract class EvaluateSettings[ScopeType]:
|
|||
private[this] final class MixedNode[Tup <: Tuple, A1](in: Tuple.Map[Tup, INode], f: Tup => A1)
|
||||
extends INode[A1]:
|
||||
import TupleMapExtension.*
|
||||
protected override def dependsOn: Seq[INode[_]] = in.iterator.toList
|
||||
protected override def dependsOn: Seq[INode[_]] = in.toList0
|
||||
protected override def evaluate0(): Unit = setValue(f(in.unmap(getValue)))
|
||||
|
||||
private[this] final class UniformNode[A1, A2](in: List[INode[A1]], f: List[A1] => A2)
|
||||
|
|
|
|||
|
|
@ -104,12 +104,12 @@ trait Init[ScopeType]:
|
|||
Optional(Some(i), f)
|
||||
|
||||
def update[A1](key: ScopedKey[A1])(f: A1 => A1): Setting[A1] =
|
||||
setting[A1](key, map(key)(f), NoPosition)
|
||||
setting[A1](key, key(f), NoPosition)
|
||||
|
||||
def flatMap[A1, A2](in: Initialize[A1])(f: A1 => Initialize[A2]): Initialize[A2] = Bind(f, in)
|
||||
|
||||
def map[A1, A2](in: Initialize[A1])(f: A1 => A2): Initialize[A2] =
|
||||
app[Tuple1[A1], A2](Tuple1(in)) { case Tuple1(x) => f(x) }
|
||||
private[this] def map[A1, A2](in: Initialize[A1])(f: A1 => A2): Initialize[A2] =
|
||||
Apply[Tuple1[A1], A2](x => f(x(0)), Tuple1(in))
|
||||
|
||||
def app[Tup <: Tuple, A2](inputs: Tuple.Map[Tup, Initialize])(f: Tup => A2): Initialize[A2] =
|
||||
Apply[Tup, A2](f, inputs)
|
||||
|
|
@ -801,7 +801,8 @@ trait Init[ScopeType]:
|
|||
(fa: Initialize[A]) => (fa.mapConstant(g))
|
||||
private[this] def evaluateK(g: Settings[ScopeType]): [A] => Initialize[A] => A = [A] =>
|
||||
(fa: Initialize[A]) => (fa.evaluate(g))
|
||||
private[this] def deps(ls: Seq[Initialize[_]]): Seq[ScopedKey[_]] = ls.flatMap(_.dependencies)
|
||||
private[this] def deps(ls: List[Initialize[_]]): Seq[ScopedKey[_]] =
|
||||
ls.flatMap(_.dependencies)
|
||||
|
||||
/**
|
||||
* An `Initialize[T]` associated with a `ScopedKey[S]`.
|
||||
|
|
@ -969,16 +970,7 @@ trait Init[ScopeType]:
|
|||
|
||||
private[sbt] override def processAttributes[A2](init: A2)(f: (A2, AttributeMap) => A2): A2 =
|
||||
inputs.foldLeft(init)((v, i) => i.processAttributes(v)(f))
|
||||
|
||||
/* private[sbt] final class Mapped[A1, A2](f: A1 => A2, input: Initialize[A1]) extends Initialize[A1]:
|
||||
override def dependencies: Seq[ScopedKey[_]] = deps(Seq(inputs))
|
||||
override def mapReferenced(g: MapScoped): Initialize[A2] = Mapped(f, input.mapReferenced(g))
|
||||
override def mapConstant(g: MapConstant): Initialize[A2] = Mapped(f, input.mapConstant(g))
|
||||
override def apply[A3](g: A2 => A3): Initialize[A3] = Mapped(g.compose(f), input)
|
||||
override def evaluate(ss: Settings[ScopeType]): A2 = f(input.evaluate(ss))
|
||||
override def validateKeyReferenced(g: ValidateKeyRef): ValidatedInit[A1] = input.validateKeyReferenced(g)
|
||||
private[sbt] override def processAttributes[A2](init: A2)(f: (A2, AttributeMap) => A2): A2 =
|
||||
input.processAttributes(init)(f) */
|
||||
end Uniform
|
||||
|
||||
private[sbt] final class Apply[Tup <: Tuple, A1](
|
||||
val f: Tup => A1,
|
||||
|
|
@ -986,7 +978,7 @@ trait Init[ScopeType]:
|
|||
) extends Initialize[A1]:
|
||||
import sbt.internal.util.TupleMapExtension.*
|
||||
|
||||
override def dependencies: Seq[ScopedKey[_]] = deps(inputs.iterator.toList)
|
||||
override def dependencies: Seq[ScopedKey[_]] = deps(inputs.toList0)
|
||||
override def mapReferenced(g: MapScoped): Initialize[A1] =
|
||||
Apply(f, inputs.transform(mapReferencedK(g)))
|
||||
override def mapConstant(g: MapConstant): Initialize[A1] =
|
||||
|
|
@ -998,13 +990,13 @@ trait Init[ScopeType]:
|
|||
|
||||
override def validateKeyReferenced(g: ValidateKeyRef): ValidatedInit[A1] =
|
||||
val tx: Tuple.Map[Tup, ValidatedInit] = inputs.transform(validateKeyReferencedK(g))
|
||||
val undefs = tx.iterator.flatMap(_.left.toSeq.flatten)
|
||||
val undefs = tx.iterator.flatMap(_.left.getOrElse(Seq.empty))
|
||||
val get = [A] => (fa: ValidatedInit[A]) => fa.toOption.get
|
||||
if undefs.isEmpty then Right(Apply(f, tx.transform(get)))
|
||||
else Left(undefs.toSeq)
|
||||
|
||||
private[sbt] override def processAttributes[A2](init: A2)(f: (A2, AttributeMap) => A2): A2 =
|
||||
inputs.iterator.toList.foldLeft(init) { (v, i) => i.processAttributes(v)(f) }
|
||||
inputs.toList0.foldLeft(init) { (v, i) => i.processAttributes(v)(f) }
|
||||
end Apply
|
||||
|
||||
private def remove[A](s: Seq[A], v: A) = s.filterNot(_ == v)
|
||||
|
|
|
|||
|
|
@ -5,28 +5,50 @@
|
|||
* Licensed under Apache License 2.0 (see LICENSE)
|
||||
*/
|
||||
|
||||
package sbt.internal
|
||||
package util
|
||||
|
||||
import sbt.util.Applicative
|
||||
package sbt.internal.util
|
||||
|
||||
object TupleMapExtension:
|
||||
extension [Tup <: Tuple, F1[_]](tuple: Tuple.Map[Tup, F1])
|
||||
def iterator: Iterator[F1[Any]] = tuple.productIterator.asInstanceOf[Iterator[F1[Any]]]
|
||||
|
||||
def unmap(f: [a] => F1[a] => a): Tup =
|
||||
Tuple.fromArray(tuple.iterator.map(f(_)).toArray).asInstanceOf[Tup]
|
||||
// typed version of tuple.toList
|
||||
def toList0: List[F1[Any]] =
|
||||
tuple.iterator.toList.asInstanceOf[List[F1[Any]]]
|
||||
|
||||
def unmap(f: [a] => F1[a] => a): Tup = transform[[A] =>> A](f).asInstanceOf[Tup]
|
||||
def transform[F2[_]](f: [a] => F1[a] => F2[a]): Tuple.Map[Tup, F2] =
|
||||
Tuple.fromArray(tuple.iterator.map(f(_)).toArray).asInstanceOf[Tuple.Map[Tup, F2]]
|
||||
|
||||
def traverse[F2[_]](f: [a] => F1[a] => F2[a])(using app: Applicative[F2]): F2[Tup] =
|
||||
val fxs: F2[List[Any]] = tuple.iterator
|
||||
.foldRight[F2[List[Any]]](app.pure(() => Nil))((x, xs) =>
|
||||
app.map(app.product(f(x), xs))((h, t) => h :: t)
|
||||
)
|
||||
app.map(fxs)(xs => Tuple.fromArray(xs.toArray).asInstanceOf[Tup])
|
||||
|
||||
def mapN[A1](f: Tup => A1)(using app: Applicative[F1]): F1[A1] =
|
||||
app.map(tuple.traverse[F1]([a] => (f: F1[a]) => f))(f)
|
||||
inline def f0(x: Any) = f(x.asInstanceOf[F1[Any]])
|
||||
// We could use tuple.map from the scala3-library but it creates temporary arrays
|
||||
// which has an impact on the performance.
|
||||
// Instead, for small tuples, of size under 22, we map over each element manually.
|
||||
// format: off
|
||||
val res = (tuple: Tuple) match
|
||||
case EmptyTuple => EmptyTuple
|
||||
case t: NonEmptyTuple =>
|
||||
t.size match
|
||||
case 1 => Tuple1(f0(t(0)))
|
||||
case 2 => (f0(t(0)), f0(t(1)))
|
||||
case 3 => (f0(t(0)), f0(t(1)), f0(t(2)))
|
||||
case 4 => (f0(t(0)), f0(t(1)), f0(t(2)), f0(t(3)))
|
||||
case 5 => (f0(t(0)), f0(t(1)), f0(t(2)), f0(t(3)), f0(t(4)))
|
||||
case 6 => (f0(t(0)), f0(t(1)), f0(t(2)), f0(t(3)), f0(t(4)), f0(t(5)))
|
||||
case 7 => (f0(t(0)), f0(t(1)), f0(t(2)), f0(t(3)), f0(t(4)), f0(t(5)), f0(t(6)))
|
||||
case 8 => (f0(t(0)), f0(t(1)), f0(t(2)), f0(t(3)), f0(t(4)), f0(t(5)), f0(t(6)), f0(t(7)))
|
||||
case 9 => (f0(t(0)), f0(t(1)), f0(t(2)), f0(t(3)), f0(t(4)), f0(t(5)), f0(t(6)), f0(t(7)), f0(t(8)))
|
||||
case 10 => (f0(t(0)), f0(t(1)), f0(t(2)), f0(t(3)), f0(t(4)), f0(t(5)), f0(t(6)), f0(t(7)), f0(t(8)), f0(t(9)))
|
||||
case 11 => (f0(t(0)), f0(t(1)), f0(t(2)), f0(t(3)), f0(t(4)), f0(t(5)), f0(t(6)), f0(t(7)), f0(t(8)), f0(t(9)), f0(t(10)))
|
||||
case 12 => (f0(t(0)), f0(t(1)), f0(t(2)), f0(t(3)), f0(t(4)), f0(t(5)), f0(t(6)), f0(t(7)), f0(t(8)), f0(t(9)), f0(t(10)), f0(t(11)))
|
||||
case 13 => (f0(t(0)), f0(t(1)), f0(t(2)), f0(t(3)), f0(t(4)), f0(t(5)), f0(t(6)), f0(t(7)), f0(t(8)), f0(t(9)), f0(t(10)), f0(t(11)), f0(t(12)))
|
||||
case 14 => (f0(t(0)), f0(t(1)), f0(t(2)), f0(t(3)), f0(t(4)), f0(t(5)), f0(t(6)), f0(t(7)), f0(t(8)), f0(t(9)), f0(t(10)), f0(t(11)), f0(t(12)), f0(t(13)))
|
||||
case 15 => (f0(t(0)), f0(t(1)), f0(t(2)), f0(t(3)), f0(t(4)), f0(t(5)), f0(t(6)), f0(t(7)), f0(t(8)), f0(t(9)), f0(t(10)), f0(t(11)), f0(t(12)), f0(t(13)), f0(t(14)))
|
||||
case 16 => (f0(t(0)), f0(t(1)), f0(t(2)), f0(t(3)), f0(t(4)), f0(t(5)), f0(t(6)), f0(t(7)), f0(t(8)), f0(t(9)), f0(t(10)), f0(t(11)), f0(t(12)), f0(t(13)), f0(t(14)), f0(t(15)))
|
||||
case 17 => (f0(t(0)), f0(t(1)), f0(t(2)), f0(t(3)), f0(t(4)), f0(t(5)), f0(t(6)), f0(t(7)), f0(t(8)), f0(t(9)), f0(t(10)), f0(t(11)), f0(t(12)), f0(t(13)), f0(t(14)), f0(t(15)), f0(t(16)))
|
||||
case 18 => (f0(t(0)), f0(t(1)), f0(t(2)), f0(t(3)), f0(t(4)), f0(t(5)), f0(t(6)), f0(t(7)), f0(t(8)), f0(t(9)), f0(t(10)), f0(t(11)), f0(t(12)), f0(t(13)), f0(t(14)), f0(t(15)), f0(t(16)), f0(t(17)))
|
||||
case 19 => (f0(t(0)), f0(t(1)), f0(t(2)), f0(t(3)), f0(t(4)), f0(t(5)), f0(t(6)), f0(t(7)), f0(t(8)), f0(t(9)), f0(t(10)), f0(t(11)), f0(t(12)), f0(t(13)), f0(t(14)), f0(t(15)), f0(t(16)), f0(t(17)), f0(t(18)))
|
||||
case 20 => (f0(t(0)), f0(t(1)), f0(t(2)), f0(t(3)), f0(t(4)), f0(t(5)), f0(t(6)), f0(t(7)), f0(t(8)), f0(t(9)), f0(t(10)), f0(t(11)), f0(t(12)), f0(t(13)), f0(t(14)), f0(t(15)), f0(t(16)), f0(t(17)), f0(t(18)), f0(t(19)))
|
||||
case 21 => (f0(t(0)), f0(t(1)), f0(t(2)), f0(t(3)), f0(t(4)), f0(t(5)), f0(t(6)), f0(t(7)), f0(t(8)), f0(t(9)), f0(t(10)), f0(t(11)), f0(t(12)), f0(t(13)), f0(t(14)), f0(t(15)), f0(t(16)), f0(t(17)), f0(t(18)), f0(t(19)), f0(t(20)))
|
||||
case 22 => (f0(t(0)), f0(t(1)), f0(t(2)), f0(t(3)), f0(t(4)), f0(t(5)), f0(t(6)), f0(t(7)), f0(t(8)), f0(t(9)), f0(t(10)), f0(t(11)), f0(t(12)), f0(t(13)), f0(t(14)), f0(t(15)), f0(t(16)), f0(t(17)), f0(t(18)), f0(t(19)), f0(t(20)), f0(t(21)))
|
||||
case _ => scala.runtime.TupleXXL.fromIterator(tuple.iterator.map(f(_)))
|
||||
// format: on
|
||||
res.asInstanceOf[Tuple.Map[Tup, F2]]
|
||||
end TupleMapExtension
|
||||
|
|
|
|||
|
|
@ -10,6 +10,18 @@ package sbt.util
|
|||
trait Applicative[F[_]] extends Apply[F]:
|
||||
def pure[A1](x: () => A1): F[A1]
|
||||
|
||||
def mapN[A1 <: Tuple, A2](t: Tuple.Map[A1, F])(f: A1 => A2): F[A2] =
|
||||
import sbt.internal.util.TupleMapExtension.*
|
||||
val g = (l: List[Any]) => f(Tuple.fromArray(l.toArray).asInstanceOf[A1])
|
||||
map(
|
||||
t.iterator.foldLeft(pure(() => g))((g, head) =>
|
||||
ap(map(head)(h => (f: List[Any] => A2) => (tail: List[Any]) => f(h :: tail)))(g)
|
||||
)
|
||||
)(_.apply(Nil))
|
||||
|
||||
def map2(t: (F[Int], F[String]))(f: (Int, String) => Boolean): F[Boolean] =
|
||||
ap(ap(pure(() => f.curried))(t._1))(t._2)
|
||||
|
||||
override def map[A1, A2](fa: F[A1])(f: A1 => A2): F[A2] =
|
||||
ap(pure(() => f))(fa)
|
||||
end Applicative
|
||||
|
|
@ -25,6 +37,8 @@ object Applicative:
|
|||
override def pure[A1](x: () => A1): F1[F2[A1]] = F1.pure(() => F2.pure(x))
|
||||
override def map[A1, A2](fa: F1[F2[A1]])(f: A1 => A2): F1[F2[A2]] =
|
||||
F1.map(fa)(f2 => F2.map(f2)(f))
|
||||
override def mapN[A1 <: Tuple, A2](t1: Tuple.Map[A1, F])(f: A1 => A2): F1[F2[A2]] =
|
||||
F1.mapN(t1.asInstanceOf[Tuple.Map[Tuple.Map[A1, F2], F1]])(t2 => F2.mapN(t2)(f))
|
||||
override def ap[A1, A2](f1f2f: F1[F2[A1 => A2]])(f1f2a: F1[F2[A1]]): F1[F2[A2]] =
|
||||
F1.ap(F1.map(f1f2f) { (f2f: F2[A1 => A2]) => (f2a: F2[A1]) => F2.ap(f2f)(f2a) })(f1f2a)
|
||||
|
||||
|
|
|
|||
|
|
@ -9,9 +9,6 @@ package sbt.util
|
|||
|
||||
trait Apply[F[_]] extends Functor[F]:
|
||||
def ap[A1, A2](ff: F[A1 => A2])(fa: F[A1]): F[A2]
|
||||
|
||||
def product[A1, A2](fa: F[A1], fb: F[A2]): F[(A1, A2)] =
|
||||
ap(map(fa)(a => (b: A2) => (a, b)))(fb)
|
||||
end Apply
|
||||
|
||||
object Apply:
|
||||
|
|
|
|||
|
|
@ -57,7 +57,7 @@ case class SettingsUsage(val settingsExample: SettingsExample) {
|
|||
// Define some settings
|
||||
val mySettings: Seq[Setting[_]] = Seq(
|
||||
setting(a3, value(3)),
|
||||
setting(b4, map(a4)(_ * 3)),
|
||||
setting(b4, a4(_ * 3)),
|
||||
update(a5)(_ + 1)
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -1,12 +0,0 @@
|
|||
package sbt.internal.util
|
||||
|
||||
import verify.BasicTestSuite
|
||||
|
||||
object TupleMapExtensionTest extends BasicTestSuite:
|
||||
val tuple: Tuple.Map[(Int, String), Option] = ((Option(1), Option("foo")))
|
||||
|
||||
test("tuple.mapN") {
|
||||
val f = (arg: (Int, String)) => arg._1.toString + "|" + arg._2
|
||||
val actual = TupleMapExtension.mapN[(Int, String), Option](tuple)(f)
|
||||
assert(actual == Option("1|foo"))
|
||||
}
|
||||
Loading…
Reference in New Issue