隐式def中的Scala更高类​​型的类型失败,并显示“找不到隐式值". [英] Scala higher kinded types in implicit def fails with "could not find implicit value"

查看:115
本文介绍了隐式def中的Scala更高类​​型的类型失败,并显示“找不到隐式值".的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用隐式def构建递归HList类型,以匹配HList的几种更高种类的类型.我深受这篇文章的启发.

I'm using implicit def to build a recursive HList type, to match several kind of higher kinded types of HList. I'm heavily inspired by this post.

此代码运行良好:

sealed trait HList {
  type Plus[L <: HList] <: HList
}

class HNil extends HList {
  type Plus[L <: HList] = L

  def ::[T](v: T) = HCons(v, this)
}

case class Appender[L1 <: HList, L2 <: HList, R <: HList](fn: (L1, L2) => R) {
  def apply(l1: L1, l2: L2) = fn(l1, l2)
}

object HNil extends HNil

object HList {
  def ++[L1 <: HList, L2 <: HList](l1: L1, l2: L2)(implicit f: Appender[L1, L2, L1#Plus[L2]]): L1#Plus[L2] = f(l1, l2)

  implicit def nilAppender[L <: HList]: Appender[HNil, L, L] = Appender((v: HNil, l: L) => l)

  implicit def consAppender[T, L1 <: HList, L2 <: HList, R <: HList](implicit f: Appender[L1, L2, R]): Appender[HCons[T, L1], L2, HCons[T, R]] = {
    Appender[HCons[T, L1], L2, HCons[T, R]]((l1: HCons[T, L1], l2: L2) => HCons(l1.head, f(l1.tail, l2)))
  }
}

case class HCons[T, U <: HList](head: T, tail: U) extends HList {
  type Plus[L <: HList] = HCons[T, U#Plus[L]]

  def ::[V](v: V) = HCons(v, this)
}

import HList._

val hlist1 = 2.0 :: "hi" :: HNil
val hlist2 = 1 :: HNil

val sum = ++(hlist1, hlist2)
println("last element : " : + sum.tail.tail.head) // prints last element : 1"

现在,我不知道为什么,但是如果我尝试在HCons上添加一个++方法,该方法只是调用现有的HList.++方法,则此方法无效:

Now, I don't know why but if I try to add a ++ method on HCons, which simply calls existing HList.++ method, this is NOT working :

 case class HCons[T, U <: HList](head: T, tail: U) extends HList {
 type Plus[L <: HList] = HCons[T, U#Plus[L]]

  def ::[V](v: V) = HCons(v, this)

  def ++[L2 <: HList](l2: L2) = HList.++(this,l2)
}

我收到此编译错误:

could not find implicit value for parameter f: Appender[HCons[T,U],L2,HCons[T,U]#Plus[L2]]

由于HConsHList的子类型,就像HList.++定义的L1类型一样,我当时认为还可以.

As HCons is a subtype of HList, like the L1 type defined by HList.++, I was thinking it was OK.

我已经尝试过了,但是效果不佳:

I've tried this but that's not working better :

implicit def consAppender[T, L1 <: HList, L2 <: HList, L3, R <: HList](implicit f: Appender[L1, L2, R], ev: L3 <:< HCons[T, L1]): Appender[HCons[T, L1], L2, HCons[T, R]] = {
    Appender[HCons[T, L1], L2, HCons[T, R]]((l1: L3, l2: L2) => HCons(l1.head, f(l1.tail, l2)))
  }

我想念什么?

谢谢:)

推荐答案

您应从以下更改++方法定义:

You should change your ++ method definition from this:

 def ++[L2 <: HList](l2: L2) = HList.++(this,l2)

对此:

def ++[L2 <: HList](l2: L2)(implicit f: Appender[HCons[T,U], L2, Plus[L2]]) = HList.++(this,l2)

编译器没有足够的信息来选择方法定义内的正确隐式值,但是当您从外部传递附加器时,此示例应传递:

The compiler doesn't have enough information to select the right implicit value inside the method definition, but when you pass the appender from the outside, this example should pass:

val hlist1 = 2.0 :: "hi" :: HNil
val hlist2 = 1 :: HNil
println(hlist1++hlist2)

更新1:HCons++方法中,我们调用HList.++方法,该方法需要一个隐式参数.此参数的类型必须为Appender[HCons[T, U], L2, HCons[T, U#Plus[L2]]].编译器可以从HList.consAppender填充此隐式参数,但这又需要另一个Appender[U, L2, U#Plus[L2]]类型的隐式参数. 这是编译器无法发现的参数.知道了这一点,上面的代码可以简化为:

Update 1: In the ++ method on HCons, we call the HList.++ method which requires an implicit parameter. This parameter must be of type Appender[HCons[T, U], L2, HCons[T, U#Plus[L2]]]. The compiler could fill this implicit parameter from HList.consAppender, but this in turn requires another implicit parameter of type Appender[U, L2, U#Plus[L2]]. This is the parameter that the compiler cannot discover itself. Knowing this, the code above can be simplified to:

def ++[L2 <: HList](l2: L2)(implicit f: Appender[U, L2, U#Plus[L2]]): Plus[L2] = HList.++(this, l2)

更新2:编译器必须在调用站点(在我们的情况下,在HCons.++方法内)填充隐式参数(可以通过例如scalac -Xprint:typer进行验证).它可以从提供两种附加类型的隐式中进行选择:

Update 2: The compiler must fill in implicit parameters at the call site, in our case inside HCons.++ method (can be verified, e.g., with scalac -Xprint:typer). It can choose from implicits providing two appender types:

Appender[HNil, L, L]
Appender[HCons[T, L1], L2, HCons[T, R]]

仅当类型参数UHNil时,才可以使用第一个,而只有当UHCons时,才可以使用第一个.但是该信息在HCons.++中不可用.它只知道U <: HList,但不知道它是HList的哪个实现,因此会失败.

The first one can be used only if type parameter U is HNil, the other only when U is HCons. But this information is not available inside HCons.++. It only knows that U <: HList but doesn't know which implementation of HList it is and therefore fails.

这篇关于隐式def中的Scala更高类​​型的类型失败,并显示“找不到隐式值".的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆