HList映射无法定义类型

时间:2018-09-30 16:43:28

标签: scala shapeless

下面,我试图在Parameter中获取HList的所有值:

import shapeless._

case class Parameter[T](value: T)

trait ParameterOperations[Params <: HList, ParamValues <: HList] {
  def values(params: Params): ParamValues
}

object ParameterOperations {

  implicit val hNil = new ParameterOperations[HNil, HNil] {
    override def values(params: HNil) = HNil
  }

  implicit def hCons[HeadParam <: Parameter[HeadParamValue], TailParams <: HList, HeadParamValue, TailParamValues <: HList](
    implicit tailParamOperations: ParameterOperations[TailParams, TailParamValues]
  ) = new ParameterOperations[HeadParam :: TailParams, HeadParamValue :: TailParamValues] {

    override def values(params: HeadParam :: TailParams): HeadParamValue :: TailParamValues =
      params.head.value :: tailParamOperations.values(params.tail)
  }
}

object Test extends App {

  def getValues[Params <: HList, ParamValues <: HList](params: Params)(
    implicit parameterOperations: ParameterOperations[Params, ParamValues]
  ) = parameterOperations.values(params)

  val b = getValues(HList(Parameter(1), Parameter(true)))
  println(b)
}

我遇到以下错误:

[error] /Users/joangoyeau/Code/autowire/autowire/jvm/src/main/scala/Test.scala:30: could not find implicit value for parameter parameterOperations: ParameterOperations[shapeless.::[Parameter[Int],shapeless.::[Parameter[Boolean],shapeless.HNil]],ParamValues]
[error]   val b = getValues(HList(Parameter(1), Parameter(true)))
[error]                    ^

ParamValues是否应该由隐式ParameterOperations定义?

1 个答案:

答案 0 :(得分:0)

要么明确指定类型参数

val b = getValues[Parameter[Int] :: Parameter[Boolean] :: HNil, Int :: Boolean :: HNil](HList(Parameter(1), Parameter(true)))

或将HeadParam从隐式hCons中排除(HeadParam不只是<: Parameter[HeadParamValue],实际上它是 Parameter[HeadParamValue]

implicit def hCons[TailParams <: HList, HeadParamValue, TailParamValues <: HList](
  implicit tailParamOperations: ParameterOperations[TailParams, TailParamValues]
) = new ParameterOperations[Parameter[HeadParamValue] :: TailParams, HeadParamValue :: TailParamValues] {

  override def values(params: Parameter[HeadParamValue] :: TailParams): HeadParamValue :: TailParamValues =
      params.head.value :: tailParamOperations.values(params.tail)
}

顺便说一句,您可以使用标准的ParameterOperationsshapeless.ops.hlist.Comapped来代替自定义类型类shapeless.ops.hlist.NatTRel

object paramToIdNatTransform extends (Parameter ~> Id) {
  override def apply[T](param: Parameter[T]): T = param.value
}

def getValues[Params <: HList, ParamValues <: HList](params: Params)(implicit
  comapped: Comapped.Aux[Params, Parameter, ParamValues],
  natTRel: NatTRel[Params, Parameter, ParamValues, Id]
): ParamValues = natTRel.map(paramToIdNatTransform, params)

val b = getValues(HList(Parameter(1), Parameter(true)))
println(b) // 1 :: true :: HNil

实际上,它甚至更简单,shapeless.ops.hlist.Mapper就足够了,因此您可以编写

val b = HList(Parameter(1), Parameter(true)).map(paramToIdNatTransform)
println(b) // 1 :: true :: HNil