HList / KList是否适合作为方法参数?怎么参考?输入清单?

时间:2012-09-03 18:07:02

标签: scala typelist hlist shapeless klist

我发现了HList / KList,它们非常酷。我有一个实际的用例,其中具有保守类型信息的异构类型和可变长度容器将非常有用(更多信息,请参见下面的背景)。但是,我还没有将H / KList的用法理解为方法参数,在这里我被迫完全键入 - 注释参数或松散类型信息。 H / KLists甚至可以用作参数,如果完整类型当然不知道? 如何在不丢失类型信息的情况下引用H / KList?

可以使用“类型列表”来指代异类和元组的元组。可变长度类型参数? Here它说: ... the types of the elements can be tracked separate from the actual element values. To do this we create an purely abstract type (it has no instances) which models a list of types, let's call it TList. 我玩过它,但还没有理解如何将它用于HList的类型注释作为参数。

基本上,我想要这样的东西:

implicit def hlistToTypedLink[TL](a: HList[TL]):TypedLink[TL] = new TypedLink[TL](a.map(a:X => new TypedHandle[X]))

其中TL表示类型列表,X表示当前元素的类型。所以这里的HList应该映射到另一个类似于Tuple的容器TypedLink,由类型列表TL进行参数化。元素将被包装在另一个参数化容器TypedHandle中,使用当前类型X键入。

这可能吗?

我看到了Shapeless的'HList及其“统一”方法,但问题仍然存在:除了可变长度之外,我不知道如何在参数列表中引用它。

我的第二个希望是使用KList。它适用于我的情况,因为TypedHandle是具有相同构造函数的公共容器。根据{{​​3}}:

,使用KList可以更轻松地输入注释
 val m = List(1, 2, 3, 4) :^: List("str1", "str2") :^: KNil

将是类型:

 KCons[Int,java.lang.String :: HNil,List]

然而,问题仍然存在:在方法定义中,我不知道它是否会是

KCons[String, Int :: HNil, TH]

KCons[Foo, Bar, Baz :: HNil, TH]

所以我不知道如何键入注释KList作为方法参数。

感谢任何提示!

背景: 我正在为优秀的OO-& amp;编写scala便利扩展。 graph database hypergraphdb。 Hypergraphdb的超边界,HGLink,基本上是HGHandle的元组。 HGHandle指的是本身键入的原子。 因此,HGLink本身将是异质类型并且具有可变长度。但是,HGLink的实现到目前为止都是无类型的,并且是由HGHandle的无类型实现构建的。我猜java的类型系统没有足够的表现力来反映hypergraphdb的(远远优越的)类型系统(例如,它也有更高的kinded类型)。

基本上,我正在尝试使用hypergraphdb的类型系统来连接scala,我正在学习很多东西,直到现在这真的很有趣。除了许多其他黑客之外,TypedHandle已经很好用了。

感谢任何建议。

2 个答案:

答案 0 :(得分:7)

我并不完全清楚你要求的是什么,但你的hlistToTypedLink似乎可以使用无形HList和多态函数值来处理,

scala> import shapeless._ ; import TypeOperators._
import shapeless._
import TypeOperators._

scala> class TypedHandle[T]
defined class TypedHandle

scala> class TypedLink[L <: HList](l : L)
defined class TypedLink

scala> object MkTypedHandle extends (Id ~> TypedHandle) {
     |   def apply[T](t : T) = new TypedHandle[T]
     | }
defined module MkTypedHandle

scala> def hlistToTypedLink[L <: HList, M <: HList](a: L)
     |   (implicit mapper: MapperAux[MkTypedHandle.type, L, M]) =
     |     new TypedLink[M](a map MkTypedHandle)
hlistToTypedLink: [L <: HList, M <: HList](a: L)
  (implicit mapper: MapperAux[MkTypedHandle.type,L,M])TypedLink[M]

scala> hlistToTypedLink(23 :: "foo" :: true :: HNil)
res0: TypedLink[TypedHandle[Int] :: TypedHandle[String] ::
  TypedHandle[Boolean] :: HNil] = TypedLink@51fb5716

基本上,您希望映射您的参数HList a,将每个元素包装在TypedHandle中,然后将生成的HList包装在{{1}中}}。在所有情况下,包装器都要精确地根据其内容的类型进行参数化。

如上所示,使用无形TypedLink HList可以实现这一点。这里有两个关键因素。首先,类似于多态函数的值map的定义可以在MkTypedHandle HList之间映射,从而创建aHList - 包裹的元素。第二,隐式证人TypedLink驱动地图操作。

答案 1 :(得分:2)

我在回复我的博文时会更好地回复。 TList只是没有值存储的HList,即只有列表的类型表示,没有运行时表示。一个优点是它有助于不同的,可能更有效的类型的值存储,例如阵列(Metascala中的HArray)。 TLists也可以用来建模联合类型(基本上是类型集),但Scala的类型系统不够强大,只能在类型级别上执行此操作(我认为Haskell的类型系统)。