2012-09-03 29 views
3

我发现了HList/KList,它们很酷。我有一个实际的用例,其中具有保存类型信息的异构类型和可变长度容器将非常有用(有关更多信息,请参阅下面的背景)。但是,我还没有理解H/KList作为方法参数的用法,我不得不完全键入注释参数或松散类型信息。 如果完整类型当然不知道,H/KList是否可以用作参数? 如何在不丢失类型信息的情况下引用H/KList?HList/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应该被映射到类型列表TL参数化的另一个类Tuple容器,TypedLink。元素将被包装在另一个参数化容器TypedHandle中,键入当前类型X.

这可能吗?

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

我的第二个希望是使用KList。它适用于我的情况,因为TypedHandle是一个具有相同构造函数的常见容器。随着KLIST它似乎更容易输入注释,根据apocalisp

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。 Hypergraphdb的hyperedges,HGLink,基本上是HGHandle的元组。 HGHandle指的是本身键入的原子。 因此,HGLink本身可能是多变类型的并且长度可变。但是,HGLink的实现到目前为止都是无类型的,并且由HGHandle的无类型实现构造。我猜java的类型系统不足以反映hypergraphdb的(远远优越的)类型系统(例如,它也有更高的kinded类型)。基本上,我试图将scala与hypergraphdb的类型系统连接起来,我学到了很多东西,直到现在,这真的很有趣。除了许多其他的黑客,TypedHandle已经很棒了。

感谢您的任何建议。

回答

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] = [email protected] 

本质上,它看起来像要映射了您的论点HLista,将每个元素包装在TypedHandle中,然后将得到的HList包装在TypedLink中。在所有情况下,包装纸都要根据其内容的类型精确地进行参数化。

如上所示,这可以使用无形的HListmap。这里有两个关键要素。首先,定义多态函数类型值MkTypedHandle,其可以跨越HLista创建的TypedLink包装的元素。第二,驱动地图操作的隐含见证mapper

+0

哇,非常感谢您花时间!我需要一些时间来消化这个,但看起来这正是我想要的!您还强调了我关于如何将HList作为方法参数的其他主要关注点。非常感谢! – ib84

2

当你参考我的博客文章时,我会更好地回应。 TList只是一个没有值存储的HList,即只有列表的类型表示,没有运行时表示。其中一个优点是它有利于不同的,可能更高效的价值存储类型,例如阵列(Metascala的HArray)。 TLists也可以用来建立联合类型(基本上是类型集合),但是Scala的类型系统不足以完全在类型级别(Haskell的类型系统)。