mirror of https://github.com/sbt/sbt.git
task system cleanup
KList.map -> transform
can now drop trailing 'H' from multi-Task 'mapH'
compressed Action hierarchy by merging (Flat)Map{ped,All,Failure} into (Flat)Mapped
moved most information in Info into attributes: AttributeMap to allow future changes
This commit is contained in:
parent
1949fe903c
commit
368bdd2701
|
|
@ -207,7 +207,7 @@ final class Execute[A[_] <: AnyRef](checkCycles: Boolean)(implicit view: NodeVie
|
|||
def submit[T]( node: A[T] )(implicit strategy: Strategy)
|
||||
{
|
||||
val v = viewCache(node)
|
||||
val rs = v.mixedIn.map(results)
|
||||
val rs = v.mixedIn transform results
|
||||
val ud = v.uniformIn.map(results.apply[v.Uniform])
|
||||
strategy.submit( node, () => work(node, v.work(rs, ud)) )
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,19 +10,11 @@ import Task._
|
|||
// Various natural transformations used, such as PMap, require invariant type constructors for correctness
|
||||
|
||||
sealed trait Action[T]
|
||||
sealed case class Pure[T](f: () => T) extends Action[T]
|
||||
|
||||
final case class Pure[T](f: () => T) extends Action[T]
|
||||
final case class Mapped[T, In <: HList](in: Tasks[In], f: Results[In] => T) extends Action[T]
|
||||
final case class MapAll[T, In <: HList](in: Tasks[In], f: In => T) extends Action[T]
|
||||
final case class MapFailure[T, In <: HList](in: Tasks[In], f: Seq[Incomplete] => T) extends Action[T]
|
||||
|
||||
final case class FlatMapAll[T, In <: HList](in: Tasks[In], f: In => Task[T]) extends Action[T]
|
||||
final case class FlatMapFailure[T, In <: HList](in: Tasks[In], f: Seq[Incomplete] => Task[T]) extends Action[T]
|
||||
final case class FlatMapped[T, In <: HList](in: Tasks[In], f: Results[In] => Task[T]) extends Action[T]
|
||||
|
||||
final case class DependsOn[T](in: Task[T], deps: Seq[Task[_]]) extends Action[T]
|
||||
|
||||
final case class Join[T, U](in: Seq[Task[U]], f: Seq[U] => Either[Task[T], T]) extends Action[T]
|
||||
final case class Join[T, U](in: Seq[Task[U]], f: Seq[Result[U]] => Either[Task[T], T]) extends Action[T]
|
||||
|
||||
object Task
|
||||
{
|
||||
|
|
@ -35,7 +27,22 @@ final case class Task[T](info: Info[T], work: Action[T])
|
|||
def original = info.original getOrElse this
|
||||
}
|
||||
/** `original` is used during transformation only.*/
|
||||
final case class Info[T](name: Option[String] = None, description: Option[String] = None, implied: Boolean = false, original: Option[Task[T]] = None)
|
||||
final case class Info[T](attributes: AttributeMap = AttributeMap.empty, original: Option[Task[T]] = None)
|
||||
{
|
||||
assert(name forall (_ != null))
|
||||
import Info._
|
||||
def name = attributes.get(Name)
|
||||
def description = attributes.get(Description)
|
||||
def implied = attributes.get(Implied).getOrElse(false)
|
||||
def setName(n: String) = set(Name, n)
|
||||
def setDescription(d: String) = set(Description, d)
|
||||
def setImplied(i: Boolean) = set(Implied, i)
|
||||
def set[T](key: AttributeKey[T], value: T) = copy(attributes = this.attributes.put(key, value))
|
||||
|
||||
}
|
||||
object Info
|
||||
{
|
||||
val Name = AttributeKey.make[String]
|
||||
val Description = AttributeKey.make[String]
|
||||
val Implied = AttributeKey.make[Boolean]
|
||||
val Cross = AttributeKey.make[AttributeMap]
|
||||
}
|
||||
|
|
@ -111,5 +111,5 @@ object Streams
|
|||
}
|
||||
|
||||
def name(a: Task[_]): String = a.info.name getOrElse anonName(a)
|
||||
def anonName(a: Task[_]) = "anon" + java.lang.Integer.toString(java.lang.System.identityHashCode(a), 36)
|
||||
def anonName(a: Task[_]) = "anon-" + java.lang.Integer.toString(java.lang.System.identityHashCode(a), 36)
|
||||
}
|
||||
|
|
@ -46,7 +46,10 @@ object System
|
|||
new (Task ~> Task) {
|
||||
def apply[T](in: Task[T]): Task[T] = {
|
||||
val finalName = in.info.name orElse staticName(in.original)
|
||||
in.copy(info = in.info.copy(name = finalName) )
|
||||
finalName match {
|
||||
case None => in
|
||||
case Some(finalName) => in.copy(info = in.info.setName(finalName) )
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -61,13 +64,12 @@ object System
|
|||
* For example, this does not include the inputs of MapFailure or the dependencies of DependsOn. */
|
||||
def usedInputs(t: Action[_]): Seq[Task[_]] = t match {
|
||||
case m: Mapped[_,_] => m.in.toList
|
||||
case m: MapAll[_,_] => m.in.toList
|
||||
case m: FlatMapped[_,_] => m.in.toList
|
||||
case m: FlatMapAll[_,_] => m.in.toList
|
||||
case j: Join[_,_] => j.in
|
||||
case _ => Nil
|
||||
}
|
||||
|
||||
|
||||
def streamed(streams: Streams, dummy: Task[TaskStreams]): Task ~> Task =
|
||||
new (Task ~> Task) {
|
||||
def apply[T](t: Task[T]): Task[T] = if(usedInputs(t.work) contains dummy) substitute(t) else t
|
||||
|
|
@ -86,10 +88,8 @@ object System
|
|||
def newWork(a: Action[T]): Task[T] = t.copy(work = a)
|
||||
|
||||
t.work match {
|
||||
case m: Mapped[_,_] => newWork( m.copy(in = m.in map depMap, f = wrap0(m.f) ) ) // the Streams instance is valid only within the mapping function
|
||||
case m: MapAll[_,_] => newWork( m.copy(in = m.in map depMap, f = wrap0(m.f) ) )
|
||||
case fm: FlatMapped[_,_] => fin(newWork( fm.copy(in = fm.in map depMap) )) // the Streams instance is valid until a result is produced for the task
|
||||
case fm: FlatMapAll[_,_] => fin(newWork( fm.copy(in = fm.in map depMap) ))
|
||||
case m: Mapped[_,_] => newWork( m.copy(in = m.in transform depMap, f = wrap0(m.f) ) ) // the Streams instance is valid only within the mapping function
|
||||
case fm: FlatMapped[_,_] => fin(newWork( fm.copy(in = fm.in transform depMap) )) // the Streams instance is valid until a result is produced for the task
|
||||
case j: Join[_,u] => newWork( j.copy(j.in map depMap.fn[u], f = wrap0(j.f)) )
|
||||
case _ => t // can't get a TaskStreams value from the other types, so no need to transform here (shouldn't get here anyway because of usedInputs check)
|
||||
}
|
||||
|
|
@ -108,6 +108,17 @@ object Transform
|
|||
def subs: Owner => Iterable[Owner]
|
||||
def static: (Owner, String) => Option[Task[_]]
|
||||
}
|
||||
def setOriginal(delegate: Task ~> Task): Task ~> Task =
|
||||
new (Task ~> Task) {
|
||||
def apply[T](in: Task[T]): Task[T] =
|
||||
{
|
||||
val transformed = delegate(in)
|
||||
if( (transformed eq in) || transformed.info.original.isDefined)
|
||||
transformed
|
||||
else
|
||||
transformed.copy(info = transformed.info.copy(original = in.info.original orElse Some(in)))
|
||||
}
|
||||
}
|
||||
|
||||
def apply[Input, State, Owner](dummies: Dummies[Input, State], injected: Injected[Input, State], context: Context[Owner]) =
|
||||
{
|
||||
|
|
@ -117,7 +128,7 @@ object Transform
|
|||
import System._
|
||||
import Convert._
|
||||
val inputs = dummyMap(dummyIn, dummyState)(in, state)
|
||||
Convert.taskToNode ∙ streamed(streams, dummyStreams) ∙ implied(owner, subs, static) ∙ name(staticName) ∙ getOrId(inputs)
|
||||
Convert.taskToNode ∙ setOriginal(streamed(streams, dummyStreams)) ∙ implied(owner, subs, static) ∙ setOriginal(name(staticName)) ∙ getOrId(inputs)
|
||||
}
|
||||
}
|
||||
object Convert
|
||||
|
|
@ -126,13 +137,9 @@ object Convert
|
|||
def apply[T](t: Task[T]): Node[Task, T] = t.work match {
|
||||
case Pure(eval) => toNode(KNil)( _ => Right(eval()) )
|
||||
case Mapped(in, f) => toNode(in)( right ∙ f )
|
||||
case MapAll(in, f) => toNode(in)( right ∙ (f compose allM) )
|
||||
case MapFailure(in, f) => toNode(in)( right ∙ (f compose anyFailM))
|
||||
case FlatMapped(in, f) => toNode(in)( left ∙ f )
|
||||
case FlatMapAll(in, f) => toNode(in)( left ∙ (f compose allM) )
|
||||
case FlatMapFailure(in, f) => toNode(in)( left ∙ (f compose anyFailM) )
|
||||
case DependsOn(in, deps) => toNode(KList.fromList(deps))( _ => Left(in) )
|
||||
case Join(in, f) => uniform(in)(f compose all)
|
||||
case Join(in, f) => uniform(in)(f)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -150,24 +157,4 @@ object Convert
|
|||
val uniformIn = Nil
|
||||
def work(results: Results[In], units: Seq[Result[Uniform]]) = f(results)
|
||||
}
|
||||
|
||||
def anyFailM[In <: HList]: Results[In] => Seq[Incomplete] = in =>
|
||||
{
|
||||
val incs = failuresM(in)
|
||||
if(incs.isEmpty) throw Incomplete(message = Some("Expected failure")) else incs
|
||||
}
|
||||
|
||||
def allM[In <: HList]: Results[In] => In = in =>
|
||||
{
|
||||
val incs = failuresM(in)
|
||||
if(incs.isEmpty) in.down(Result.tryValue) else throw Incomplete(causes = incs)
|
||||
}
|
||||
def all[D]: Seq[Result[D]] => Seq[D] = in =>
|
||||
{
|
||||
val incs = failures(in)
|
||||
if(incs.isEmpty) in.map(Result.tryValue.fn[D]) else throw Incomplete(causes = incs)
|
||||
}
|
||||
def failuresM[In <: HList]: Results[In] => Seq[Incomplete] = x => failures[Any](x.toList)
|
||||
def failures[A](results: Seq[Result[A]]): Seq[Incomplete] = results.collect { case Inc(i) => i }
|
||||
|
||||
}
|
||||
|
|
@ -13,7 +13,7 @@ sealed trait MultiInTask[In <: HList]
|
|||
{
|
||||
def flatMap[T](f: In => Task[T]): Task[T]
|
||||
def flatMapR[T](f: Results[In] => Task[T]): Task[T]
|
||||
def mapH[T](f: In => T): Task[T]
|
||||
def map[T](f: In => T): Task[T]
|
||||
def mapR[T](f: Results[In] => T): Task[T]
|
||||
def flatFailure[T](f: Seq[Incomplete] => Task[T]): Task[T]
|
||||
def mapFailure[T](f: Seq[Incomplete] => T): Task[T]
|
||||
|
|
@ -51,14 +51,14 @@ import java.io._
|
|||
sealed trait BinaryPipe
|
||||
{
|
||||
def binary[T](f: BufferedInputStream => T): Task[T]
|
||||
//def binary[T](sid: String)(f: BufferedInputStream => T): Task[T]
|
||||
def binary[T](sid: String)(f: BufferedInputStream => T): Task[T]
|
||||
def #>(f: File): Task[Unit]
|
||||
//def #>(sid: String, f: File): Task[Unit]
|
||||
def #>(sid: String, f: File): Task[Unit]
|
||||
}
|
||||
sealed trait TextPipe
|
||||
{
|
||||
def text[T](f: BufferedReader => T): Task[T]
|
||||
//def #| [T](sid: String)(f: BufferedReader => T): Task[T]
|
||||
def text[T](sid: String)(f: BufferedReader => T): Task[T]
|
||||
}
|
||||
sealed trait TaskLines
|
||||
{
|
||||
|
|
@ -67,7 +67,7 @@ sealed trait TaskLines
|
|||
}
|
||||
sealed trait ProcessPipe {
|
||||
def #| (p: ProcessBuilder): Task[Int]
|
||||
//def #| (sid: String)(p: ProcessBuilder): Task[Int]
|
||||
def pipe(sid: String)(p: ProcessBuilder): Task[Int]
|
||||
}
|
||||
|
||||
trait TaskExtra
|
||||
|
|
@ -84,35 +84,36 @@ trait TaskExtra
|
|||
}
|
||||
final implicit def pureJoin[S](in: Seq[S]): JoinTask[S, Seq] = joinTasks(pureTasks(in))
|
||||
final implicit def joinTasks[S](in: Seq[Task[S]]): JoinTask[S, Seq] = new JoinTask[S, Seq] {
|
||||
def join: Task[Seq[S]] = new Join(in, (s: Seq[S]) => Right(s) )
|
||||
//def join[T](f: Iterable[S] => T): Task[Iterable[T]] = new MapAll( MList.fromTCList[Task](in), ml => f(ml.toList))
|
||||
//def joinR[T](f: Iterable[Result[S]] => T): Task[Iterable[Result[T]]] = new Mapped( MList.fromTCList[Task](in), ml => f(ml.toList))
|
||||
def join: Task[Seq[S]] = new Join(in, (s: Seq[Result[S]]) => Right(TaskExtra.all(s)) )
|
||||
def reduce(f: (S,S) => S): Task[S] = TaskExtra.reduce(in.toIndexedSeq, f)
|
||||
}
|
||||
|
||||
final implicit def multInputTask[In <: HList](tasks: Tasks[In]): MultiInTask[In] = new MultiInTask[In] {
|
||||
def flatMap[T](f: In => Task[T]): Task[T] = new FlatMapAll(tasks, f)
|
||||
import TaskExtra.{allM, anyFailM}
|
||||
|
||||
def flatMapR[T](f: Results[In] => Task[T]): Task[T] = new FlatMapped(tasks, f)
|
||||
def mapH[T](f: In => T): Task[T] = new MapAll(tasks, f)
|
||||
def flatMap[T](f: In => Task[T]): Task[T] = flatMapR(f compose allM)
|
||||
def flatFailure[T](f: Seq[Incomplete] => Task[T]): Task[T] = flatMapR(f compose anyFailM)
|
||||
|
||||
def mapR[T](f: Results[In] => T): Task[T] = new Mapped(tasks, f)
|
||||
def flatFailure[T](f: Seq[Incomplete] => Task[T]): Task[T] = new FlatMapFailure(tasks, f)
|
||||
def mapFailure[T](f: Seq[Incomplete] => T): Task[T] = new MapFailure(tasks, f)
|
||||
def map[T](f: In => T): Task[T] = mapR(f compose allM)
|
||||
def mapFailure[T](f: Seq[Incomplete] => T): Task[T] = mapR(f compose anyFailM)
|
||||
}
|
||||
|
||||
final implicit def singleInputTask[S](in: Task[S]): SingleInTask[S] = new SingleInTask[S] {
|
||||
import TaskExtra.{successM, failM}
|
||||
|
||||
type HL = S :+: HNil
|
||||
private val ml = in :^: KNil
|
||||
private def headM = (_: Results[HL]).combine.head
|
||||
private def headH = (_: HL).head
|
||||
private def headS = (_: Seq[Incomplete]).head
|
||||
|
||||
def flatMapR[T](f: Result[S] => Task[T]): Task[T] = new FlatMapped[T, HL](ml, f ∙ headM)
|
||||
def flatMap[T](f: S => Task[T]): Task[T] = new FlatMapAll(ml, f ∙ headH)
|
||||
def flatFailure[T](f: Incomplete => Task[T]): Task[T] = new FlatMapFailure(ml, f ∙ headS)
|
||||
|
||||
def map[T](f: S => T): Task[T] = new MapAll(ml, f ∙ headH)
|
||||
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)
|
||||
|
||||
def mapR[T](f: Result[S] => T): Task[T] = new Mapped[T, HL](ml, f ∙ headM)
|
||||
def mapFailure[T](f: Incomplete => T): Task[T] = new MapFailure(ml, f ∙ headS)
|
||||
def map[T](f: S => T): Task[T] = mapR(f compose successM)
|
||||
def mapFailure[T](f: Incomplete => T): Task[T] = mapR(f compose failM)
|
||||
|
||||
def dependsOn(tasks: Task[_]*): Task[S] = new DependsOn(in, tasks)
|
||||
def andFinally(fin: => Unit): Task[S] = mapR(x => Result.tryValue[S]( { fin; x }))
|
||||
|
|
@ -121,14 +122,14 @@ trait TaskExtra
|
|||
def && [T](alt: Task[T]): Task[T] = flatMap( _ => alt )
|
||||
}
|
||||
final implicit def toTaskInfo[S](in: Task[S]): TaskInfo[S] = new TaskInfo[S] {
|
||||
def named(s: String): Task[S] = in.copy(info = in.info.copy(name = Some(s)))
|
||||
def describedAs(s: String): Task[S] = in.copy(info = in.info.copy(description = Some(s)))
|
||||
def implies: Task[S] = in.copy(info = in.info.copy(implied = true))
|
||||
def named(s: String): Task[S] = in.copy(info = in.info.setName(s))
|
||||
def describedAs(s: String): Task[S] = in.copy(info = in.info.setDescription(s))
|
||||
def implies: Task[S] = in.copy(info = in.info.setImplied(true))
|
||||
}
|
||||
|
||||
final implicit def pipeToProcess(t: Task[_])(implicit streams: Task[TaskStreams]): ProcessPipe = new ProcessPipe {
|
||||
def #| (p: ProcessBuilder): Task[Int] = pipe0(None, p)
|
||||
//def #| (sid: String)(p: ProcessBuilder): Task[Int] = pipe0(Some(sid), p)
|
||||
def pipe(sid: String)(p: ProcessBuilder): Task[Int] = pipe0(Some(sid), p)
|
||||
private def pipe0(sid: Option[String], p: ProcessBuilder): Task[Int] =
|
||||
for(s <- streams; in <- s.readBinary(t, sid, true)) yield {
|
||||
val pio = TaskExtra.processIO(s).withInput( out => { BasicIO.transferFully(in, out); out.close() } )
|
||||
|
|
@ -138,10 +139,10 @@ trait TaskExtra
|
|||
|
||||
final implicit def binaryPipeTask(in: Task[_])(implicit streams: Task[TaskStreams]): BinaryPipe = new BinaryPipe {
|
||||
def binary[T](f: BufferedInputStream => T): Task[T] = pipe0(None, f)
|
||||
//def #| [T](sid: String)(f: BufferedInputStream => T): Task[T] = pipe0(Some(sid), f)
|
||||
def binary[T](sid: String)(f: BufferedInputStream => T): Task[T] = pipe0(Some(sid), f)
|
||||
|
||||
def #>(f: File): Task[Unit] = pipe0(None, toFile(f))
|
||||
//def #>(sid: String, f: File): Task[Unit] = pipe0(Some(sid), toFile(f))
|
||||
def #>(sid: String, f: File): Task[Unit] = pipe0(Some(sid), toFile(f))
|
||||
|
||||
private def pipe0 [T](sid: Option[String], f: BufferedInputStream => T): Task[T] =
|
||||
streams flatMap { s => s.readBinary(in, sid, true) map f }
|
||||
|
|
@ -150,7 +151,7 @@ trait TaskExtra
|
|||
}
|
||||
final implicit def textPipeTask(in: Task[_])(implicit streams: Task[TaskStreams]): TextPipe = new TextPipe {
|
||||
def text[T](f: BufferedReader => T): Task[T] = pipe0(None, f)
|
||||
//def #| [T](sid: String)(f: BufferedReader => T): Task[T] = pipe0(Some(sid), f)
|
||||
def text [T](sid: String)(f: BufferedReader => T): Task[T] = pipe0(Some(sid), f)
|
||||
|
||||
private def pipe0 [T](sid: Option[String], f: BufferedReader => T): Task[T] =
|
||||
streams flatMap { s => s.readText(in, sid, true) map f }
|
||||
|
|
@ -185,5 +186,29 @@ object TaskExtra extends TaskExtra
|
|||
reducePair( reduce(a, f), reduce(b, f), f )
|
||||
}
|
||||
def reducePair[S](a: Task[S], b: Task[S], f: (S, S) => S): Task[S] =
|
||||
(a :^: b :^: KNil) mapH { case x :+: y :+: HNil => f(x,y) }
|
||||
(a :^: b :^: KNil) map { case x :+: y :+: HNil => f(x,y) }
|
||||
|
||||
def anyFailM[In <: HList]: Results[In] => Seq[Incomplete] = in =>
|
||||
{
|
||||
val incs = failuresM(in)
|
||||
if(incs.isEmpty) expectedFailure else incs
|
||||
}
|
||||
def failM[T]: Result[T] => Incomplete = { case Inc(i) => i; case x => expectedFailure }
|
||||
|
||||
def expectedFailure = throw Incomplete(message = Some("Expected failure"))
|
||||
|
||||
def successM[T]: Result[T] => T = { case Inc(i) => throw i; case Value(t) => t }
|
||||
def allM[In <: HList]: Results[In] => In = in =>
|
||||
{
|
||||
val incs = failuresM(in)
|
||||
if(incs.isEmpty) in.down(Result.tryValue) else throw Incomplete(causes = incs)
|
||||
}
|
||||
def failuresM[In <: HList]: Results[In] => Seq[Incomplete] = x => failures[Any](x.toList)
|
||||
|
||||
def all[D](in: Seq[Result[D]]) =
|
||||
{
|
||||
val incs = failures(in)
|
||||
if(incs.isEmpty) in.map(Result.tryValue.fn[D]) else throw Incomplete(causes = incs)
|
||||
}
|
||||
def failures[A](results: Seq[Result[A]]): Seq[Incomplete] = results.collect { case Inc(i) => i }
|
||||
}
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
/* sbt -- Simple Build Tool
|
||||
* Copyright 2010 Mark Harrah
|
||||
*/
|
||||
package sbt
|
||||
|
||||
import Types._
|
||||
|
||||
// T must be invariant to work properly.
|
||||
// Because it is sealed and the only instances go through make,
|
||||
// a single AttributeKey instance cannot conform to AttributeKey[T] for different Ts
|
||||
sealed trait AttributeKey[T]
|
||||
object AttributeKey
|
||||
{
|
||||
def make[T]: AttributeKey[T] = new AttributeKey[T] {}
|
||||
}
|
||||
|
||||
trait AttributeMap
|
||||
{
|
||||
def apply[T](k: AttributeKey[T]): T
|
||||
def get[T](k: AttributeKey[T]): Option[T]
|
||||
def contains[T](k: AttributeKey[T]): Boolean
|
||||
def put[T](k: AttributeKey[T], value: T): AttributeMap
|
||||
}
|
||||
object AttributeMap
|
||||
{
|
||||
def empty: AttributeMap = new BasicAttributeMap(Map.empty)
|
||||
}
|
||||
private class BasicAttributeMap(backing: Map[AttributeKey[_], Any]) extends AttributeMap
|
||||
{
|
||||
def apply[T](k: AttributeKey[T]) = backing(k).asInstanceOf[T]
|
||||
def get[T](k: AttributeKey[T]) = backing.get(k).asInstanceOf[Option[T]]
|
||||
def contains[T](k: AttributeKey[T]) = backing.contains(k)
|
||||
def put[T](k: AttributeKey[T], value: T): AttributeMap = new BasicAttributeMap( backing.updated(k, value) )
|
||||
}
|
||||
|
|
@ -9,21 +9,23 @@ import Types._
|
|||
* type parameters HL. The underlying data is M applied to each type parameter.
|
||||
* Explicitly tracking M[_] allows performing natural transformations or ensuring
|
||||
* all data conforms to some common type. */
|
||||
sealed trait KList[+M[_], +HL <: HList] {
|
||||
sealed trait KList[+M[_], +HL <: HList]
|
||||
{
|
||||
type Raw = HL
|
||||
/** Transform to the underlying HList type.*/
|
||||
def down(implicit ev: M ~> Id): HL
|
||||
/** Apply a natural transformation. */
|
||||
def map[N[_]](f: M ~> N): KList[N, HL]
|
||||
def transform[N[_]](f: M ~> N): KList[N, HL]
|
||||
/** Convert to a List. */
|
||||
def toList: List[M[_]]
|
||||
/** Convert to an HList. */
|
||||
def combine[N[X] >: M[X]]: HL#Wrap[N]
|
||||
}
|
||||
|
||||
final case class KCons[H, T <: HList, +M[_]](head: M[H], tail: KList[M,T]) extends KList[M, H :+: T] {
|
||||
def down(implicit f: M ~> Id) = HCons(f(head), tail.down(f))
|
||||
def map[N[_]](f: M ~> N) = KCons( f(head), tail.map(f) )
|
||||
final case class KCons[H, T <: HList, +M[_]](head: M[H], tail: KList[M,T]) extends KList[M, H :+: T]
|
||||
{
|
||||
def down(implicit f: M ~> Id) = HCons(f(head), tail down f)
|
||||
def transform[N[_]](f: M ~> N) = KCons( f(head), tail transform f )
|
||||
// prepend
|
||||
def :^: [N[X] >: M[X], G](g: N[G]) = KCons(g, this)
|
||||
def toList = head :: tail.toList
|
||||
|
|
@ -31,9 +33,10 @@ final case class KCons[H, T <: HList, +M[_]](head: M[H], tail: KList[M,T]) exten
|
|||
def combine[N[X] >: M[X]]: (H :+: T)#Wrap[N] = HCons(head, tail.combine)
|
||||
}
|
||||
|
||||
sealed class KNil extends KList[Nothing, HNil] {
|
||||
sealed class KNil extends KList[Nothing, HNil]
|
||||
{
|
||||
def down(implicit f: Nothing ~> Id) = HNil
|
||||
def map[N[_]](f: Nothing ~> N) = KNil
|
||||
def transform[N[_]](f: Nothing ~> N) = KNil
|
||||
def :^: [M[_], H](h: M[H]) = KCons(h, this)
|
||||
def toList = Nil
|
||||
def combine[N[X]] = HNil
|
||||
|
|
|
|||
|
|
@ -8,4 +8,8 @@ object Types extends TypeFunctions
|
|||
val :^: = KCons
|
||||
val :+: = HCons
|
||||
type :+:[H, T <: HList] = HCons[H,T]
|
||||
|
||||
implicit def hconsToK[M[_], H, T <: HList](h: M[H] :+: T)(implicit mt: T => KList[M, T]): KList[M, H :+: T] =
|
||||
KCons[H, T, M](h.head, mt(h.tail) )
|
||||
implicit def hnilToK(hnil: HNil): KNil = KNil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ object KTest {
|
|||
val f = new (Option ~> List) { def apply[T](o: Option[T]): List[T] = o.toList }
|
||||
|
||||
val x = Some(3) :^: Some("asdf") :^: KNil
|
||||
val y = x map f
|
||||
val y = x transform f
|
||||
val m1a = y match { case List(3) :^: List("asdf") :^: KNil => println("true") }
|
||||
val m1b = (List(3) :^: KNil) match { case yy :^: KNil => println("true") }
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue