Scala:递归模式匹配异构列表,获取每个元素的正确类型

时间:2018-07-02 23:43:16

标签: scala generics generic-programming shapeless

我正在尝试执行以下操作,也就是说,每次将头传递给通用函数时,都要通过匹配头和尾的模式来递归处理HList

import shapeless._
trait MyTrait {

  def myFunc[T](x: String => T): Boolean

  def iter(myHList: HList, acc: List[Boolean]): List[Boolean] = {
    myHList match {
      case HNil => acc
      case head :: tail => myFunc(head) :: iter(tail, acc)
    }
  }
}

问题是我从匹配中得到的头部类型为Any,而不是我放入HList中的头部类型。我希望将head作为参数的函数具有正确的类型参数T

这可能吗?也许除了Shapeless以外还有其他方法吗?

1 个答案:

答案 0 :(得分:0)

尝试

def iter(myHList: HList, acc: List[Boolean]): List[Boolean] = {
  (myHList: @unchecked) match {
    case HNil => acc
    case (head: Function1[String, _] @unchecked) :: tail => 
      myFunc(head) :: iter(tail, acc)
  }
}

(第一个@unchecked禁止警告模式匹配不完整,第二个@unchecked禁止警告由于类型擦除而导致未经检查的通用String)。

或者,您可以更安全地匹配类型。但是通常写一个参数只是一个HList而不是一个特定的A :: B :: ... :: HNil太粗糙了。由于您的函数对不同类型的值(即HNilH :: T)的作用不同,因此它是Poly

object iter extends Poly2 {
  implicit val nilCase: Case.Aux[HNil, List[Boolean], List[Boolean]] = 
    at((_, acc) => acc)

  implicit def consCase[A, T <: HList](implicit 
    tailCase: Case.Aux[T, List[Boolean], List[Boolean]]
    ): Case.Aux[(String => A) :: T, List[Boolean], List[Boolean]] =
    at { case (head :: tail, acc) => myFunc(head) :: iter(tail, acc) }
}

用法:

def myFunc[T](x: String => T): Boolean = true

iter(((s: String) => s.toUpperCase) :: ((s: String) => s.length) :: HNil, List[Boolean]()) 
// List(true, true)