我链接转换,并且我希望累积每次转换的结果,以便它可以在任何后续步骤中使用,并且还使所有结果在最后都可用(主要用于调试目的)。有几个步骤,我不时需要添加一个新步骤或更改步骤的输入。
HList
似乎提供了一种以灵活但仍然是类型安全的方式收集结果的便捷方式。但我并不是通过让它们处理HList和随附的业务而使实际步骤复杂化。
这是我想写的组合器的简化版本,它不起作用。该想法是给定包含A的HList和A的索引,以及来自A - >的函数。 B,mapNth
将提取A,运行函数,并将结果汇总到列表中。生成的扩展列表捕获新结果的类型,因此可以组合其中几个mapNth-ified步骤以生成包含每个步骤结果的列表:
def mapNth[L <: HList, A, B]
(l: L, index: Nat, f: A => B)
(implicit at: shapeless.ops.hlist.At[L, index.N]):
B :: L =
f(l(index)) :: l
顺便说一下,我还需要map2Nth
取两个索引和f: (A, B) => C
,但我相信问题是一样的。
但是,mapNth
无法编译,说l(index)
的类型为at.Out
,但f
的参数应为A
。当然,这是正确的,所以我认为我需要的是一种提供at.Out
实际上是A
(或at.Out <: A
)的证据的方式。
有没有办法表达这种约束?我认为它必须采取隐式的形式,因为当然{} {}被应用于特定的列表和函数时,只能检查约束。
答案 0 :(得分:3)
您完全正确地需要at.Out
A
的证据,并且您可以通过在at
&#39;中包含类型成员的值来提供该证据。 s类型:
def mapNth[L <: HList, A, B]
(l: L, index: Nat, f: A => B)
(implicit at: shapeless.ops.hlist.At[L, index.N] { type Out = A }):
B :: L =
f(l(index)) :: l
Shapeless中类型类At
的伴随对象也定义了Aux
类型,其中包含输出类型作为最终类型参数。
def mapNth[L <: HList, A, B]
(l: L, index: Nat, f: A => B)
(implicit at: shapeless.ops.hlist.At.Aux[L, index.N, A]):
B :: L =
f(l(index)) :: l
这几乎相当,但更惯用(而且看起来更好)。