我正在尝试使这个相当愚蠢的示例工作,然后计划将其扩展到更有意义的地方。

但到目前为止还没有运气:我收到了could not find implicit value for parameter ihc
我想念什么?

sealed trait Field[T] { def name: String }
case class IntegerField(name: String) extends Field[Int]
val year = IntegerField("year")

val test = (year :: 23 :: HNil) :: (year :: 2 :: HNil) :: HNil

type TypedMap = IntegerField ::  Int  :: HNil

def get[L <: HList : <<:[TypedMap]#λ]
      (key: IntegerField, list: L)
      (implicit ihc: IsHCons.Aux[L, TypedMap, L]
    ): Option[Int] = {

  if( list == HNil ) return None
  val elem: TypedMap = list.head
  if( elem.head == key ) Some(elem.tail.head)
  else get(key, list.tail)

}

get(year, test)

最佳答案

当您编写IsHCons.Aux[L, TypedMap, L]时,您要寻求证据证明hlist L具有head TypedMap和tail L,这意味着它是一个无限的hlist,这是不可能的,因为Scala不允许这种任意的递归类型(尝试例如,编写类似type Foo = Int :: Foo的代码-您会收到“非法循环引用”错误)。它也可能不是您想要的。

通常,您不太可能在Shapeless中使用IsHCons,因为仅在类型中指示所需的结构几乎总会更好。例如,以下两个定义执行相同的操作:

import shapeless._, ops.hlist.IsHCons

def foo[L <: HList](l: L)(implicit ev: IsHCons[L]) = ev.head(l)

和:
def foo[H, T <: HList](l: H :: T) = l.head

但是第二个显然是更好的选择(更清楚的是,它不需要在编译时找到额外的类型类实例,等等),并且几乎总是可以用这种方式编写任何内容。

还要注意,需要IsHCons实例意味着此处的递归将无法按所述方式工作-您不能在get上调用HNil,因为编译器无法证明它是HCons(因为不是)。

您确定您完全需要一个 list 吗?如果您要求hlist的所有成员都为TypedMap类型,则不妨使用Shapeless的Sized(如果您希望该类型捕获长度),甚至可以仅使用普通的旧List

如果您确实要在此处使用HList,建议您编写一个新的类型类:
trait FindField[L <: HList] {
  def find(key: IntegerField, l: L): Option[Int]
}

object FindField {
  implicit val findFieldHNil: FindField[HNil] = new FindField[HNil] {
    def find(key: IntegerField, l: HNil) = None
  }

  implicit def findFieldHCons[H <: TypedMap, T <: HList](implicit
    fft: FindField[T]
  ): FindField[H :: T] = new FindField[H :: T] {
    def find(key: IntegerField, l: H :: T) = if (l.head.head == key)
      Some(l.head.tail.head)
    else fft.find(key, l.tail)
  }
}

def get[L <: HList](key: IntegerField, l: L)(implicit
  ffl: FindField[L]
): Option[Int] = ffl.find(key, l)

然后:
scala> get(IntegerField("year"), test)
res3: Option[Int] = Some(23)

scala> get(IntegerField("foo"), test)
res4: Option[Int] = None

这是Shapeless中非常常见的模式-您可以归纳地描述如何在空的hlist上执行操作,然后在头上有尾部的hlist上执行操作,等等。

关于scala - 无形:IsHCons,未发现隐式,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/29331173/

10-11 08:17