从HList检索元素的函数(同时保留其类型)

时间:2018-11-20 07:34:48

标签: scala shapeless hlist

我有这种类型,可以通过无形生成:

type hlistt = STUDENT.type :: AUTO_LOANS.type :: HNil

基本上,我有一堆扩展特性的case对象,因此我设法创建了一种方法,该方法将所有case对象的实例作为HList给出

然后使用import shapeless.ops.hlist.Lastinit写了一个方法,如果值等于字符串“ student”,则可以检索HList中的一个节点:

def getLast(hl:hlistt) = {
  val last0=Last[hlistt]
  val la=last0(hl)

  if (la.value == "student") la
  else init(hl)
}

问题在于,如果我调用此方法,我将无法从HList获取正确的节点类型。

getLast(STUDENT :: AUTO_LOANS :: HNil)

该方法有效并返回节点,但是类型为关闭:

Product with Serializable = STUDENT :: HNil

我需要一些见证/辅助隐式返回正确的类型吗?

2 个答案:

答案 0 :(得分:1)

我不太确定您想做什么。鉴于:

type hlistt = STUDENT.type :: AUTO_LOANS.type :: HNil

Last[hlistt]将解析为AUTO_LOANS.type(如果为分支则为真) 而init将解析为STUDENT :: HNil(如果为分支则为假)

这些类型的LUB(最小上限)将为Product with Serializable,所以这就是您看到它的原因。

如果要检查hlist成员的运行时属性,则必须通过使用适当的机制派生适当的类型边界和结果类型来进行线程化。在这种情况下,它是无形的。

https://scalafiddle.io/sf/fdtn3cz/0

这是您想要的吗?

编辑: 我也刚读

  

我有这种类型,可以动态生成:

“动态”到底是什么意思?因为除非您可以指定一些编译时属性,否则shapeless可能不是您想要的解决方案。

答案 1 :(得分:1)

la的类型为AUTO_LOANS.typeinit(hl)的类型为STUDENT.type :: HNil,所以

if (la.value == "student") la
else init(hl)

类型为Any(或Product with Serializable)。

如果您想从不同的分支返回不同类型的值,则需要一个Poly

import shapeless.{Poly1, Witness}

object myPoly extends Poly1 {
  implicit def studentCase: Case.Aux[Witness.`"student"`.T, STUDENT.type] = 
    at(_ => STUDENT)
  implicit def autoLoansCase: Case.Aux[Witness.`"auto-loans"`.T, AUTO_LOANS.type] = 
    at(_ => AUTO_LOANS)
}

import shapeless.syntax.singleton._
println(
  myPoly("student".narrow)
) // STUDENT

println(
  myPoly("auto-loans".narrow)
) // AUTO_LOANS

// println(
//   myPoly("abc".narrow)
// )  // doesn't compile

如果在编译时知道字符串,则此方法有效。