无形HList appender

时间:2017-09-30 18:37:21

标签: scala shapeless

我正在尝试编写一个附加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类型比类型中的元素长一个?

2 个答案:

答案 0 :(得分:3)

使用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))
  }

答案 1 :(得分:1)

对于后代,这是一个使用你的长度检查想法的答案。但LacksKey方式更好。此外,Updater如果您重用密钥但使用不同的类型(因为,毕竟,类型实际上是密钥的一部分),会创建重复密钥,这意味着此append执行相同的操作。 / p>

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))

请注意,计算中的所有类型级别值都需要是类型参数,因为您不能使用在同一参数列表中提及其他参数的类型的参数。你需要非常小心,不要让编译器做更多的事情,而不是处理每一步。