为 HList 类型构建类型类实例列表

Build list of typeclass instances for HList type

我正在尝试改进我们 API 之一的类型。我想创建具有以下签名的数据提取器:

def runIt[T <: HList](id: Int): T = ???

它应该获取某些实体的调用外部服务器和 return 具有所需数据的 HList。第一项任务是为所需功能构建 API 参数列表。

这是我做的:

import shapeless._
import shapeless.ops.hlist._

trait Feature

trait FeatureFetcher[T] {
  def name: String
}

trait F1 extends Feature
trait F2 extends Feature

implicit case object f1Fetcher extends FeatureFetcher[F1] {
  val name = "f1name"
}

implicit case object f2Fetcher extends FeatureFetcher[F2] {
  val name = "f2name"
}

def makeIt[T <: HList](id: Int)
                      (implicit liftAll: LiftAll[FeatureFetcher, T]) = {

  // I need this, but it does not compile here
  // liftAll.instances.toList.map(_.name).mkString(",")

  liftAll.instances
}

makeIt[F1 :: F2 :: HNil](1).toList.map(_.name).mkString(",")

它确实有效。但是当我将 .toList 移动到 makeIt 函数时,我得到错误

Error:(25, 21) could not find implicit value for parameter toTraversableAux: shapeless.ops.hlist.ToTraversable.Aux[liftAll.Out,List,Lub]
liftAll.instances.toList.map(_.name).mkString(",")

如何解决这个问题?

我认为当代码使用 implicit liftAll: LiftAll[FeatureFetcher, T] 调用隐式实例时,LiftAll 的依赖类型 Out of LiftAll 将丢失,因此编译器不知道哪种类型的实例将 return,因此错误。

一个可能的解决方案是使用,使用 shapeless 中的 the,这应该是更好的隐式方法。

the[liftAll].instances.toList

如果有帮助请告诉我!!

基于 segeljakt,尝试通过 LiftAll.AuxliftAll.Out 传递给 ToTraversable.Aux

def makeIt[In <: HList, Out <: HList](id: Int)(implicit
  liftAll: LiftAll.Aux[FeatureFetcher, In, Out],
  toTraversable: ToTraversable.Aux[Out, List, FeatureFetcher[_]]
): String = {
  liftAll.instances.toList.map(_.name).mkString(",")
}

type In = F1 :: F2 :: HNil
type Out = FeatureFetcher[F1] :: FeatureFetcher[F2] :: HNil
makeIt[In, Out](1)
// res1: String = f1name,f2name

或基于ToElmTypes

case class MakeIt[In <: HList]() {
  def apply[Out <: HList](id: Int)(implicit
    liftAll: LiftAll.Aux[FeatureFetcher, In, Out],
    toTraversable: ToTraversable.Aux[Out, List, FeatureFetcher[_]]
  ): String = {
    liftAll.instances.toList.map(_.name).mkString(",")
  }
}

MakeIt[F1 :: F2 :: HNil].apply(1)