我发现了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已经很好用了。
感谢任何建议。
答案 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
之间映射,从而创建a
个HList
- 包裹的元素。第二,隐式证人TypedLink
驱动地图操作。
答案 1 :(得分:2)
我在回复我的博文时会更好地回复。 TList只是没有值存储的HList,即只有列表的类型表示,没有运行时表示。一个优点是它有助于不同的,可能更有效的类型的值存储,例如阵列(Metascala中的HArray)。 TLists也可以用来建模联合类型(基本上是类型集),但Scala的类型系统不够强大,只能在类型级别上执行此操作(我认为Haskell的类型系统)。