Shapeless的HList内容类型推论

4

这个例子被简化了。

我有一组类像这样:

case class KeyMapping[KeyType](k:KeyType)

class WrappedMapping[KeyType](m:T forSome {type T <: KeyMapping[KeyType]}) {
  val k:KeyType = ???
}

在以下代码中,类型被正确推断出:
 val w = new WrappedMapping(KeyMapping("key"))

 //The statement below gives the correct error
 //type mismatch; 
 //  found : w.k.type (with underlying type String)  required: Nothing
 //val test1:Nothing = w.k

我不知道如何正确推断以下内容的类型:

class Mappings[KeyType, L <: HList](mappings:L) {
  val k:KeyType = ???
}

val m = new Mappings(KeyMapping("key1") :: KeyMapping("key2") :: HNil)

// should not compile, k should be of type String
val test2:Nothing = m.k

有没有一种方法可以根据的内容推断?

你为什么不使用签名 class WrappedMapping[KeyType](m: KeyMapping[KeyType]) 呢?现在,那个存在类型显得很突兀,这肯定会让问题变得更难回答。 - Kevin Wright
其实不用了,我发现WrappedMapping没有在Mappings中使用。 - Kevin Wright
你只是想确认 HList 中的所有映射都具有相同的键类型吗?目标有点不清楚。 - Travis Brown
我希望在“Mappings”中的“KeyType”可以通过键类型的上限进行推断。如果正确推断的唯一解决方案是只允许一种类型的键,那也没关系。只要它是从“HList”中的“KeyMappings”中推断出来的即可。 - EECOLOR
1个回答

8

Shapeless提供了一个ToList隐式转换,用于将HLists转换为Lists。

为了实现这一点,它必须首先计算HList中类型的最小上界(LUB),这是可以使用的:

import shapeless.ops.hlist.ToList

class Mappings[L <: HList, Lub](mappings:L)(implicit toList: ToList[L, Lub]) {
  ...
}

L进入时,隐式解析会发现受到该L限制的唯一有效ToList实例,其Lub类型被拉出。

但这还不够,因为Lub将是KeyMapping[String],而你想要的只是String部分。 像往常一样,使用shapeless的解决方法是添加另一个隐式:

class Mappings[L <: HList, Lub, KeyType](mappings:L)(
  implicit
  val toList: ToList[L, Lub],
  val kt: Lub <:< KeyMapping[KeyType]
) {
  val k: KeyType = null.asInstanceOf[KeyType]
}

(implicit的不需要是val,但当你在REPL中探索时设置为val会更有帮助)

这个表述的意思是Lub对应于类型KeyMapping[KeyType](例如,它是一个子类型或完全相同的类型),其中KeyType尚未知道。再次强调,对指定的约束条件只有一种有效的解决方案,并将KeyType参数提取为String

我不知道你计划如何实现k,但你可能发现具有toList实例可以帮助你这样做,因为它允许你现在调用mappings.toList


就像我之前所说的,这只是一个简化的例子。我不会实现 k,但我确实需要正确推断出 KeyType(以及类似的东西)。如果我能完成这个库,我会发布链接的。 - EECOLOR

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接