在 class 中使用 ReplaceAt

use ReplaceAt inside a class

我正在为 Shapeless HList 构建一个包装器,我想使用 updatedAt 函数来更新 HList 中的值,但我似乎无法正确理解隐式。这是我认为最接近可行解决方案的两个版本:

class Data[L <: HList](val hl: L) {

  def updatedAtV1[V](n : Nat, value : V)(implicit 
         replacer : ReplaceAt[L, n.N, V]) : replacer.Out = replacer(hl, value)

  def updatedAtV2[V, Out <: HList](n : Nat, value : V)(implicit
         replacer : ReplaceAt.Aux[L, n.N, V, (V, Out)]) : Out = replacer(hl, value)._2

}

V1 编译,但是因为它 returns 一个 Tuple 我无法将它强制为 Tuple 类型所以我无法得到 replacer(hl, value)._2 元素。在 V2 中,编译器无法解析 Out 类型。

请注意 V2 工作正常,如果该值与它替换的类型相同,但如果它是不同的类型则失败。

由于这个隐含的原因,它不适用于不同的类型:

ReplaceAt.Aux[L, n.N, V, (V, Out)] 

你说你想在 n 处放置一个 V 类型的值,然后从 HList 中取回 V。您可以通过引入额外的类型参数来修复它:

def updatedAtV3[V, W, Out <: HList](n : Nat, value : V)(implicit
  replacer : ReplaceAt.Aux[L, n.N, V, (W, Out)]) : Out = replacer(hl, value)._2

那里 W - 列表中已经存在的元素 - 可以是任何东西(它将从隐式参数中推断出来),所以一切正常:

new Data(1 :: HNil).updatedAtV3(0, 42) == 42 :: HNil    
new Data(1 :: HNil).updatedAtV3(0, "foo") == "foo" :: HNil