我正在尝试实现通用功能以获取第一个元素:

import shapeless.ops.hlist.IsHCons
import shapeless.{Generic, HList}

object App {

  def main(args : Array[String]) {
    val a: Int = getFirst((1, 2, 3))
    val b: String = getFirst(("a", "b", 10, 45, "aaa"))
  }

  def getFirst[A, Head, Repr <: HList, Tail <: HList](input: A)
                                                     (implicit hcons: IsHCons.Aux[Repr, Head, Tail],
                                                      gen: Generic.Aux[A, Repr]): Head = gen.to(input).head
}


问题是编译器无法正确推断ReprTail并将它们设置为Nothing。就这个:

Error:(9, 26) could not find implicit value for parameter gen: shapeless.Generic.Aux[(Int, Int, Int),Repr]
    val a: Int = getFirst((1, 2, 3))
Error:(9, 26) not enough arguments for method getFirst: (implicit hcons: shapeless.ops.hlist.IsHCons.Aux[Nothing :: Nothing,Head,Tail], implicit gen: shapeless.Generic.Aux[(Int, Int, Int),Nothing :: Nothing])Head.
Unspecified value parameter gen.
    val a: Int = getFirst((1, 2, 3))
Error:(10, 29) could not find implicit value for parameter gen: shapeless.Generic.Aux[(String, String, Int),Repr]
    val b: String = getFirst(("a", "b", 10))
Error:(10, 29) not enough arguments for method getFirst: (implicit hcons: shapeless.ops.hlist.IsHCons.Aux[Nothing :: Nothing,Head,Tail], implicit gen: shapeless.Generic.Aux[(String, String, Int),Nothing :: Nothing])Head.
Unspecified value parameter gen.
    val b: String = getFirst(("a", "b", 10))


解决该问题的解决方案是什么?可以肯定以下工作正常:

val a: Int = getFirst[(Int, Int, Int), Int, Int :: Int :: Int :: HNil, Int :: Int :: HNil]((1, 2, 3))


但这非常麻烦和丑陋。

最佳答案

解决方案是交换隐式参数顺序-首先交换Generic,然后交换IsHCons

  def getFirst[A, Head, Repr <: HList, Tail <: HList](input: A)
                                                     (implicit gen: Generic.Aux[A, Repr], hcons: IsHCons.Aux[Repr, Head, Tail]
                                                      ): Head = gen.to(input).head


(scastie)

我不知道它是如何工作的,但是我已经看到通过解析隐式来推断类型参数从左到右起作用。

因此,使用您的签名,Scala首先查找IsHCons.Aux[Repr, Head, Tail],但此时对Repr的了解不多,只是它是一个HList。它会找到某个实例-可能是针对类似Nothing :: HList的实例,然后尝试查找Generic.Aux[A, Nothing :: HList](从A推断出input),该实例失败,因为这对于Generic而言不是有效的A

关于scala - HList的无形类型推断不起作用,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/59318077/

10-10 06:02