-
Notifications
You must be signed in to change notification settings - Fork 12
Expand file tree
/
Copy pathKList.scala
More file actions
58 lines (48 loc) · 1.79 KB
/
KList.scala
File metadata and controls
58 lines (48 loc) · 1.79 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
import HList.{:: => :+: }
import ~>._
import KList._
/** A higher-order heterogeneous list. It has a type constructor M[_] and
* 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] {
type Raw = HL
/** Convert 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]
/** Convert to a List. */
def toList: List[M[_]]
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) )
// prepend
def :^: [N[X] >: M[X], G](g: N[G]) = KCons(g, this)
def toList = head :: tail.toList
def combine[N[X] >: M[X]]: (H :+: T)#Wrap[N] = HCons(head, tail.combine)
}
sealed class KNil extends KList[Nothing, HNil] {
def down(implicit f: Nothing ~> Id) = HNil
def map[N[_]](f: Nothing ~> N) = KNil
def :^: [M[_], H](h: M[H]) = KCons(h, this)
def toList = Nil
def combine[N[X]] = HNil
}
object KNil extends KNil
object KList
{
// nicer alias for pattern matching
val :^: = KCons
}
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
y match { case List(3) :^: List("asdf") :^: KNil => println("true") }
val head = new (List ~> Id) { def apply[T](xs: List[T]): T = xs.head }
val z = y down head
// pattern matching with :^: without 'down' doesn't work (Id again)
z match { case 3 :+: "asdf" :+: HNil => println("true") }
}