3

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

“类型列表”可以用来指代异构和可变长度类型参数的元组吗?这里它说: ... 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 是具有相同构造函数的通用容器。根据 apocalisp 的说法,使用 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- 和图形数据库 hypergraphdb 编写 scala 便利扩展。Hypergraphdb 的超边 HGLink 基本上是 HGHandle 的元组。HGHandle 指的是本身有类型的原子。因此 HGLink 本身将是异构类型和可变长度的。但是,到目前为止,HGLink 的实现是无类型的,并且是由 HGHandle 的无类型实现构建的。我猜 java 的类型系统的表现力不足以反映 hypergraphdb 的(非常优秀的)类型系统(例如,它也有更高种类的类型)。

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

感谢您的任何建议。

4

2 回答 2

8

我并不完全清楚你要什么,但你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,将每个元素包装在 a 中TypedHandle,然后将结果包装HList在 a 中TypedLink。在所有情况下,包装器都将根据其内容的类型精确地参数化。

如上所示,这可以使用 shapeless 的HList map. 这里有两个关键成分。首先,定义多态类函数值MkTypedHandle,它可以映射到HList a创建一个HList-wrappedTypedLink元素。mapper其次,驱动地图操作的隐式见证。

于 2012-09-03T19:46:27.857 回答
2

当您参考我的博客文章时,我会更好地回应。TList 只是一个没有值存储的 HList,即只有列表的类型表示,没有运行时表示。一个优点是它促进了不同的、可能更有效的值存储类型,例如数组(Metascala 中的 HArray)。TLists 也可以用于对联合类型(基本上是类型集)进行建模,但是 Scala 的类型系统不足以仅在类型级别上做到这一点(我认为是 Haskell 的类型系统)。

于 2012-09-04T10:56:05.323 回答