编译时两个相同大小的 HList 的总和?
Sum of Two Identically Sized HList's at Compile-Time?
鉴于以下尝试检索两个 HList
的递归和,如下所示:
(请暂时原谅其名称中的 Product
。)
package net
import shapeless._
import shapeless.nat._
import shapeless.ops.nat.{Sum, Prod, Mod}
trait SumZippedProduct[L, M] {
type S
}
object SumZippedProduct {
type Aux[L, M, O] = SumZippedProduct[L, M] {
type S = O
}
def apply[L <: HList, M <: HList](implicit ev: SumZippedProduct[L, M]) = ev
// LH - L's head
// L - HList
// MH - M's head
// M - HList
// RS - Recursive Sum (L + H)
// CS - Current Sum (LH + RH)
// E - RS + CS
implicit def sumZippedInductiveEq5[LH <: Nat, L <: HList, MH <: Nat, M <: HList, RS <: Nat, CS <: Nat, E <: Nat](
implicit ev: SumZippedProduct.Aux[L, M, RS],
curr: Sum.Aux[LH, MH, CS],
total: Sum.Aux[CS, RS, E]
): SumZippedProduct[LH :: L, MH :: M] = new SumZippedProduct[LH :: L, MH :: M] {
type S = E
}
implicit val hnils: SumZippedProduct[HNil, HNil] = new SumZippedProduct[HNil, HNil] {
type S = _0
}
}
尝试时,我认为它适用于 HNil
情况,但不适用于 1 元素 HList
:
scala> import net.SumZippedProduct
import net.SumZippedProduct
scala> import shapeless._, nat._
import shapeless._
import nat._
// expecting 0 (0 + 0)
scala> SumZippedProduct[HNil, HNil]
res0: net.SumZippedProduct[shapeless.HNil,shapeless.HNil] = net.SumZippedProduct$$anon@794b4359
// expecting _4 (1 + 3)
scala> SumZippedProduct[_1 :: HNil, _3 :: HNil]
<console>:19: error: could not find implicit value for parameter ev: net.SumZippedProduct[shapeless.::[shapeless.nat._1,shapeless.HNil],shapeless.::[shapeless.nat._3,shapeless.HNil]]
SumZippedProduct[_1 :: HNil, _3 :: HNil]
^
为什么传_1 :: HNil
和_3 :: HNil
不编译?
此外,我怎样才能在 res0
中获得 _0
?
scala> res0.S
<console>:20: error: value S is not a member of net.SumZippedProduct[shapeless.HNil,shapeless.HNil]
res0.S
^
注意 - 如果这样的实现已经存在于 shapeless 中,我很感激,但我问这个问题是为了学习。
您必须在隐含的 return 类型中使用 Aux
。否则 S
的具体类型将会丢失。
对于 summon 方法 apply
你也必须使用更精确的 return 类型,出于同样的原因。由于 SumZippedProduct
扩展了 AnyRef
你可以只使用 ev.type
;没有比这更精确的了。
scala> :paste
// Entering paste mode (ctrl-D to finish)
import shapeless._
import shapeless.nat._
import shapeless.ops.nat.{Sum, Prod, Mod, ToInt}
trait SumZippedProduct[L, M] {
type S <: Nat
final def S(implicit toInt: ToInt[S]): Int = toInt()
}
object SumZippedProduct {
type Aux[L, M, O] = SumZippedProduct[L, M] {
type S = O
}
def apply[L <: HList, M <: HList](implicit ev: SumZippedProduct[L, M]): ev.type = ev
implicit def sumZippedInductiveEq5[LH <: Nat, L <: HList, MH <: Nat, M <: HList, RS <: Nat, CS <: Nat, E <: Nat](
implicit ev: SumZippedProduct.Aux[L, M, RS],
curr: Sum.Aux[LH, MH, CS],
total: Sum.Aux[CS, RS, E]
): SumZippedProduct.Aux[LH :: L, MH :: M, E] = new SumZippedProduct[LH :: L, MH :: M] {
type S = E
}
implicit val hnils: SumZippedProduct.Aux[HNil, HNil, _0] = new SumZippedProduct[HNil, HNil] {
type S = _0
}
}
// Exiting paste mode, now interpreting.
import shapeless._
import shapeless.nat._
import shapeless.ops.nat.{Sum, Prod, Mod}
defined trait SumZippedProduct
defined object SumZippedProduct
scala> SumZippedProduct[HNil, HNil]
res1: SumZippedProduct.<refinement>.type = SumZippedProduct$$anon@673bac03
scala> val a: res1.S = _0
a: res1.S = shapeless._0@4f450e01
scala> SumZippedProduct[_1 :: HNil, _3 :: HNil]
res2: SumZippedProduct.Aux[shapeless.::[shapeless.nat._1,shapeless.HNil],shapeless.::[shapeless.nat._3,shapeless.HNil],this.Out] = SumZippedProduct$$anon@2a53bcfa
scala> val a: res2.S = _4
a: res2.S = Succ()
scala> val a: res2.S = _5
<console>:26: error: type mismatch;
found : shapeless.nat._5
(which expands to) shapeless.Succ[shapeless.Succ[shapeless.Succ[shapeless.Succ[shapeless.Succ[shapeless._0]]]]]
required: res2.S
(which expands to) shapeless.Succ[shapeless.Succ[shapeless.Succ[shapeless.Succ[shapeless._0]]]]
val a: res2.S = _5
^
scala> res2.S
res3: Int = 4
我还添加了生成相应整数值的方法。我实际上并不知道现有的方法可以从 Nat
类型中调用 Nat
值(或者我只是瞎了眼...)。但我认为在大多数情况下 Nat
仅在类型级别有用,您更愿意在值级别使用实际的 Int
s。
如果您真的想要值级别 Nat
s,那么自己实现也不难。但是如果你看看它们在 shapeless 中的实现,它们实际上只是空盒子,所以你对它们无能为力。只有它们的类型有用。
鉴于以下尝试检索两个 HList
的递归和,如下所示:
(请暂时原谅其名称中的 Product
。)
package net
import shapeless._
import shapeless.nat._
import shapeless.ops.nat.{Sum, Prod, Mod}
trait SumZippedProduct[L, M] {
type S
}
object SumZippedProduct {
type Aux[L, M, O] = SumZippedProduct[L, M] {
type S = O
}
def apply[L <: HList, M <: HList](implicit ev: SumZippedProduct[L, M]) = ev
// LH - L's head
// L - HList
// MH - M's head
// M - HList
// RS - Recursive Sum (L + H)
// CS - Current Sum (LH + RH)
// E - RS + CS
implicit def sumZippedInductiveEq5[LH <: Nat, L <: HList, MH <: Nat, M <: HList, RS <: Nat, CS <: Nat, E <: Nat](
implicit ev: SumZippedProduct.Aux[L, M, RS],
curr: Sum.Aux[LH, MH, CS],
total: Sum.Aux[CS, RS, E]
): SumZippedProduct[LH :: L, MH :: M] = new SumZippedProduct[LH :: L, MH :: M] {
type S = E
}
implicit val hnils: SumZippedProduct[HNil, HNil] = new SumZippedProduct[HNil, HNil] {
type S = _0
}
}
尝试时,我认为它适用于 HNil
情况,但不适用于 1 元素 HList
:
scala> import net.SumZippedProduct
import net.SumZippedProduct
scala> import shapeless._, nat._
import shapeless._
import nat._
// expecting 0 (0 + 0)
scala> SumZippedProduct[HNil, HNil]
res0: net.SumZippedProduct[shapeless.HNil,shapeless.HNil] = net.SumZippedProduct$$anon@794b4359
// expecting _4 (1 + 3)
scala> SumZippedProduct[_1 :: HNil, _3 :: HNil]
<console>:19: error: could not find implicit value for parameter ev: net.SumZippedProduct[shapeless.::[shapeless.nat._1,shapeless.HNil],shapeless.::[shapeless.nat._3,shapeless.HNil]]
SumZippedProduct[_1 :: HNil, _3 :: HNil]
^
为什么传_1 :: HNil
和_3 :: HNil
不编译?
此外,我怎样才能在 res0
中获得 _0
?
scala> res0.S
<console>:20: error: value S is not a member of net.SumZippedProduct[shapeless.HNil,shapeless.HNil]
res0.S
^
注意 - 如果这样的实现已经存在于 shapeless 中,我很感激,但我问这个问题是为了学习。
您必须在隐含的 return 类型中使用 Aux
。否则 S
的具体类型将会丢失。
对于 summon 方法 apply
你也必须使用更精确的 return 类型,出于同样的原因。由于 SumZippedProduct
扩展了 AnyRef
你可以只使用 ev.type
;没有比这更精确的了。
scala> :paste
// Entering paste mode (ctrl-D to finish)
import shapeless._
import shapeless.nat._
import shapeless.ops.nat.{Sum, Prod, Mod, ToInt}
trait SumZippedProduct[L, M] {
type S <: Nat
final def S(implicit toInt: ToInt[S]): Int = toInt()
}
object SumZippedProduct {
type Aux[L, M, O] = SumZippedProduct[L, M] {
type S = O
}
def apply[L <: HList, M <: HList](implicit ev: SumZippedProduct[L, M]): ev.type = ev
implicit def sumZippedInductiveEq5[LH <: Nat, L <: HList, MH <: Nat, M <: HList, RS <: Nat, CS <: Nat, E <: Nat](
implicit ev: SumZippedProduct.Aux[L, M, RS],
curr: Sum.Aux[LH, MH, CS],
total: Sum.Aux[CS, RS, E]
): SumZippedProduct.Aux[LH :: L, MH :: M, E] = new SumZippedProduct[LH :: L, MH :: M] {
type S = E
}
implicit val hnils: SumZippedProduct.Aux[HNil, HNil, _0] = new SumZippedProduct[HNil, HNil] {
type S = _0
}
}
// Exiting paste mode, now interpreting.
import shapeless._
import shapeless.nat._
import shapeless.ops.nat.{Sum, Prod, Mod}
defined trait SumZippedProduct
defined object SumZippedProduct
scala> SumZippedProduct[HNil, HNil]
res1: SumZippedProduct.<refinement>.type = SumZippedProduct$$anon@673bac03
scala> val a: res1.S = _0
a: res1.S = shapeless._0@4f450e01
scala> SumZippedProduct[_1 :: HNil, _3 :: HNil]
res2: SumZippedProduct.Aux[shapeless.::[shapeless.nat._1,shapeless.HNil],shapeless.::[shapeless.nat._3,shapeless.HNil],this.Out] = SumZippedProduct$$anon@2a53bcfa
scala> val a: res2.S = _4
a: res2.S = Succ()
scala> val a: res2.S = _5
<console>:26: error: type mismatch;
found : shapeless.nat._5
(which expands to) shapeless.Succ[shapeless.Succ[shapeless.Succ[shapeless.Succ[shapeless.Succ[shapeless._0]]]]]
required: res2.S
(which expands to) shapeless.Succ[shapeless.Succ[shapeless.Succ[shapeless.Succ[shapeless._0]]]]
val a: res2.S = _5
^
scala> res2.S
res3: Int = 4
我还添加了生成相应整数值的方法。我实际上并不知道现有的方法可以从 Nat
类型中调用 Nat
值(或者我只是瞎了眼...)。但我认为在大多数情况下 Nat
仅在类型级别有用,您更愿意在值级别使用实际的 Int
s。
如果您真的想要值级别 Nat
s,那么自己实现也不难。但是如果你看看它们在 shapeless 中的实现,它们实际上只是空盒子,所以你对它们无能为力。只有它们的类型有用。