无形 HList appender
Shapeless HList appender
我正在尝试编写一个可以附加 HList
的函数,我发现 Updater
最接近我想要的:
def appender[L <: HList, V, Out <: HList](hl: L, k: Witness, v: V)(implicit updater: Updater.Aux[L, FieldType[k.T, V], Out]) : Out = {
updater(hl, field[k.T](v))
}
我有更新和追加 HList 的函数,但我想禁用更新并只允许函数追加,因此:
val hl = 'field1 ->> 1 :: HNil
appender(hl, 'field2, 2) //should compile
appender(hl, 'field1, 2) //should fail
目前都可以编译。无论如何,我可以用 Shapeless 表达这种约束吗?我想也许可以询问 Out
类型比 in 类型长一个元素的证据?
使用shapeless.ops.record.LacksKey
:
def appender[L <: HList, V, Out <: HList](hl: L, k: Witness, v: V)(implicit
updater: Updater.Aux[L, FieldType[k.T, V], Out],
lk: LacksKey[L, k.T]) : Out = {
updater(hl, field[k.T](v))
}
为了后代,这里有一个使用您的长度检查想法的答案。不过,LacksKey
方法更好。此外,如果您重复使用一个键但使用不同的类型,Updater
会创建重复的键(因为毕竟类型实际上是键的一部分),这意味着这个 append
也是如此。
def append[
Value,
In <: HList,
Out <: HList,
InSize <: Nat,
OutSize <: Nat,
AddedNum <: Nat
](in: In, key: Witness, value: Value)(implicit
update: Updater.Aux[In, FieldType[key.T, Value], Out],
inSize: Length.Aux[In, InSize],
outSize: Length.Aux[Out, OutSize],
addedNum: ops.nat.Diff.Aux[OutSize, InSize, AddedNum], // ops.{hlist, nat}.Diff conflict
sizeRestriction: AddedNum =:= _1 // Bonus: error messages are fairly readable: "Cannot prove that AddedNum = Succ[_0]" (followed by a horrifyingly long "not enough arguments" error).
): Out = update(in, field[key.T](value))
请注意,计算中的所有类型级值都必须是类型参数,因为您不能在同一参数列表中使用提及其他参数的类型的参数。您需要非常小心,永远不要要求编译器做超过它可以处理的每一步的事情。
我正在尝试编写一个可以附加 HList
的函数,我发现 Updater
最接近我想要的:
def appender[L <: HList, V, Out <: HList](hl: L, k: Witness, v: V)(implicit updater: Updater.Aux[L, FieldType[k.T, V], Out]) : Out = {
updater(hl, field[k.T](v))
}
我有更新和追加 HList 的函数,但我想禁用更新并只允许函数追加,因此:
val hl = 'field1 ->> 1 :: HNil
appender(hl, 'field2, 2) //should compile
appender(hl, 'field1, 2) //should fail
目前都可以编译。无论如何,我可以用 Shapeless 表达这种约束吗?我想也许可以询问 Out
类型比 in 类型长一个元素的证据?
使用shapeless.ops.record.LacksKey
:
def appender[L <: HList, V, Out <: HList](hl: L, k: Witness, v: V)(implicit
updater: Updater.Aux[L, FieldType[k.T, V], Out],
lk: LacksKey[L, k.T]) : Out = {
updater(hl, field[k.T](v))
}
为了后代,这里有一个使用您的长度检查想法的答案。不过,LacksKey
方法更好。此外,如果您重复使用一个键但使用不同的类型,Updater
会创建重复的键(因为毕竟类型实际上是键的一部分),这意味着这个 append
也是如此。
def append[
Value,
In <: HList,
Out <: HList,
InSize <: Nat,
OutSize <: Nat,
AddedNum <: Nat
](in: In, key: Witness, value: Value)(implicit
update: Updater.Aux[In, FieldType[key.T, Value], Out],
inSize: Length.Aux[In, InSize],
outSize: Length.Aux[Out, OutSize],
addedNum: ops.nat.Diff.Aux[OutSize, InSize, AddedNum], // ops.{hlist, nat}.Diff conflict
sizeRestriction: AddedNum =:= _1 // Bonus: error messages are fairly readable: "Cannot prove that AddedNum = Succ[_0]" (followed by a horrifyingly long "not enough arguments" error).
): Out = update(in, field[key.T](value))
请注意,计算中的所有类型级值都必须是类型参数,因为您不能在同一参数列表中使用提及其他参数的类型的参数。您需要非常小心,永远不要要求编译器做超过它可以处理的每一步的事情。