【问题标题】:Is there a way to derive implicits for each member of an HList from Scala Shapeless?有没有办法从 Scala Shapeless 为 HList 的每个成员派生隐含?
【发布时间】:2020-04-04 22:43:48
【问题描述】:

我尝试了以下方法:

type Params = String :: Int :: HNil

implicit val params: Params = "hello" :: 5 :: HNil

// Supposed to create an implicit for string and int if needed
implicit def meberImplicit[A](
  implicit 
  params: Params,
  selector: Selector[Params, A]
): A = params.select[A]

// Summoning a string
implicitly[String]    // compile-time error

但是,我得到了一个发散的隐含错误:

diverging implicit expansion for type String

我在这里遗漏了什么吗?也许已经有内置的或更好的方法来实现这一点?

【问题讨论】:

标签: scala implicit shapeless


【解决方案1】:

问题是你太笼统了

implicit def memberImplicit[A](
  implicit // what you put here is irrelevant
): A = ...

您基本上为任何值提供了隐式。这与您定义的任何其他隐式以及您需要获取的任何隐式参数发生冲突。

但是让我们问一下为什么编译器不能证明你只是不能提供你传递给memberImplicit 的隐含处理不好的情况,所以它不会认为它是一个可行的选择,所以它能够证明这个应该削减派生的分支(在你不打算这样做的地方),解决歧义,然后蛋糕。

问题是,您返回的类型是A。这意味着即使您在那里添加了一些约束,例如A =:!= Params - 虽然通常它会起作用......你只是提供了所有这些隐式,所以类型约束停止工作,并且突然衍生出诸如Selector[Params, String] 有不止一种实例化方式。在这种情况下,几乎任何你尝试的实现——只要它返回A——都会失败。

为了使事情正常工作,您必须将输出限制为不匹配所有内容的内容 - 事实上,匹配越少越好。例如,创建一个单独的类型类来从 HLists 中提取值:

trait Extractable[A] { def extract(): A }
object Extractable {
  implicit def extractHList[H <: HList, A](
    implicit
    h: H,
    selector: Selector[H, A]
  ): Extractable[A] = () => selector(h)
}

def extract[A](implicit extractable: Extractable[A]): A = extractable.extract()

然后

extract[String] // "hello"

【讨论】:

  • Error: value extract is not a member of type parameter H selector(h.extract())
  • 现在试试,我不小心留下了旧尝试的一行
  • 我明白了。我一直怀疑它与返回类型有关。谢谢。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-09-29
  • 1970-01-01
  • 2021-07-24
  • 1970-01-01
  • 2010-09-25
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多