复合材料的Scala类型类

复合材料的Scala类型类,scala,typeclass,scala-cats,Scala,Typeclass,Scala Cats,我有一个和类型,映射: sealed trait Mapping final case class XMapping(a:String) final case class FallbackMapping(mappings: List[Mapping]) 我有一个typeclass,定义如下: final case class Param(x:String) trait ParameterLoader[T] { def load(mapping:T) : List[Param] } 在某

我有一个和类型,映射:

sealed trait Mapping
final case class XMapping(a:String)
final case class FallbackMapping(mappings: List[Mapping])
我有一个typeclass,定义如下:

final case class Param(x:String)

trait ParameterLoader[T] {
  def load(mapping:T) : List[Param]
}
在某些情况下:

object DefaultParameterLoaders {
  implicit val  xParameterLoader= new QueryParameterLoader[XMapping] {
    override def load(mapping: XMapping): List[Param] = List(Param(mapping.a))
  }

  implicit val fallbackParameterLoader = new ParameterLoader[FallbackMapping] {

    override def load(mapping: FallbackMapping): List[Param] =
      mapping.mappings.flatMap(x => ???)

  }
}

我找不到将隐式实例传递到上面的flatMap的方法。我得到的错误是缺少ParameterLoader[Mapping]的一个实例。有没有办法告诉编译器应该使用范围内的任何类型类实例

类型系统正在寻找一个
ParameterLoader[Mapping]
,这意味着
ParameterLoader[XMapping]
/
ParameterLoader[FallbackMapping]
不够具体。您需要提供一个
参数加载器[映射]
。可以使用现有的定义执行此操作

implicit def mappingLoader(implicit xpLoader: ParameterLoader[XMapping], fmLoader: ParameterLoader[FallbackMapping]) = new ParameterLoader[Mapping] { 
  def load(mapping: Mapping): List[QueryParam] = 
    mapping match {
      case xm: XMapping = xpLoader.load(xm)
      case fm: FallbackMapping => fmLoader.load(fm)
    }
}
或者,让flatmap执行匹配逻辑:

implicit def fallbackParameterLoader(implicit xpLoader: ParameterLoader[XMapping]) = new ParameterLoader[FallbackMapping] {
  override def load(mapping: FallbackMapping): List[Param] =
    mapping.mappings.flatMap { 
      case xm: XMapping = xpLoader.load(xm)
      case fm: FallbackMapping => this.load(fm)
    }
  }

谢谢这很有效。我希望能以某种方式实现自动化。这将锁定所使用的实例,而理想情况下,我希望使用客户机范围内的任何实例。可能吗?是的。不要像我所做的那样显式地指定参数加载器,而是隐式地使用
ParameterLoader[XMapping].load(xm)
代替
xParameterLoader.load(xm)
。但是,这将使用在构建参数加载器时在范围内的参数加载器。我已经更新了我的答案以支持您的用例。这将基于范围内的任何参数加载程序派生mappingLoader。请记住,有这样的派生,行为可能会令人困惑,因为导入可以改变行为。确保这是一个很好的文档,让你的团队知道它是如何工作的。如果你有任何其他问题,请随时提问。