-
Notifications
You must be signed in to change notification settings - Fork 2
/
Nested.scala
94 lines (88 loc) · 2.53 KB
/
Nested.scala
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
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
package org.hammerlab.shapeless.nesting.seq
import shapeless._
import shapeless.nat._
/**
* Type-class for counting and homogenizing nested types comprised of nested [[Seq]]-applications
*
* Output types:
*
* - `N`: number of levels of [[Seq]] (or its implementations) that comprise [[In]]
* - `Out`: `N` levels of vanilla [[Seq]] applied to the same underlying type as [[In]]
*
* Includes an `apply` method for converting an instence of [[In]] to an `Out`
*
* @tparam In input-type
*/
sealed trait Nested[In] {
type N <: Nat
type Out
@inline def apply(in: In): Out
}
trait LowPri {
type Aux[In, _N <: Nat, _Out] =
Nested[In] {
type N = _N
type Out = _Out
}
/**
* Base case: [[_0 0]] levels of [[Seq]] to unroll/homogenize/re-roll
*/
implicit def zero[T]: Aux[T, _0, T] =
new Nested[T] {
type N = _0
type Out = T
def apply(in: T): Out = in
}
}
object Nested
extends LowPri {
/**
* [[Range]]s get special-cased since they mask one level of [[Seq]]-wrapping, and aren't picked up by [[cons]]
* below
*/
implicit def range[R <: Range]:
Aux[
R,
_1,
Seq[Int]
] =
new Nested[R] {
type N = _1
type Out = Seq[Int]
def apply(in: R): Out = in
}
/**
* Inductive step: if we can convert a [[PrevIn]] to a [[PrevOut]], the latter being [[Seq]] (or one of its
* subtypes) applied [[_N]] times, then [[I]] (a [[Seq]]-subtype) applied to [[PrevIn]] can be converted to [[_N]]+1
* applications of [[Seq]]
*
* @param r converter from [[PrevIn]] to [[PrevOut]]; homogenizes [[_N]] levels of [[Seq]]-application
* @tparam _N previous number of levels of [[Seq]]-application
* @tparam I a [[Seq]] sub-type; will be coerced to [[Seq]] itself on the output type of the returned [[Nested]]
* instance
* @tparam PrevIn previous input type; [[_N]] levels of application of [[Seq]]-subtypes
* @tparam PrevOut previous output type; [[_N]] levels of application of [[Seq]]
* @return a [[Nested]] instance that can convert [[I]]⊙[[PrevIn]] to [[Seq]]⊙[[PrevOut]], additionally recording
* that this represents [[_N]]+1 levels of conversion
*/
implicit def cons[
_N <: Nat,
I[T] <: Seq[T],
PrevIn,
PrevOut
](
implicit
r: Lazy[Aux[PrevIn, _N, PrevOut]]
):
Aux[
I[PrevIn],
Succ[_N],
Seq[PrevOut]
] =
new Nested[I[PrevIn]] {
type N = Succ[_N]
type Out = Seq[r.value.Out]
def apply(in: I[PrevIn]): Out =
in.map(r.value(_))
}
}