隐式映射器对隐式映射参数的奇怪影响

时间:2016-06-30 16:49:58

标签: scala shapeless hlist

假设我有容器标记

case class TypedString[T](value: String)

和部分功能技巧

abstract class PartFunc[Actual <: HList] {
    val poly: Poly

    def apply[L1 <: HList](l: L1)(implicit
                                  mapped: Mapped.Aux[Actual, TypedString, L1],
                                  mapper: Mapper[poly.type, L1]): L1 = l
}

Poly for Mapper

object f extends (TypedString ~>> String) {
    def apply[T](s : TypedString[T]) = s.value
}

和结果方法

def func[Actual <: HList] = new PartFunc[Actual] {
    val poly = f
}

使用示例:

func[
    Int :: String :: HNil
](TypedString[Int]("42") :: TypedString[String]("hello") :: HNil)

此代码在编译时失败,因为编译器找不到Mapped隐式参数:

could not find implicit value for parameter mapped: 
    shapeless.ops.hlist.Mapped[shapeless.::[Int,shapeless.::[String,shapeless.HNil]],nottogether.MapperTest.TypedString]{type Out = shapeless.::[nottogether.MapperTest.TypedString[Int],shapeless.::[nottogether.MapperTest.TypedString[String],shapeless.HNil]]}
        ](TypedString[Int]("42") :: TypedString[String]("hello") :: HNil)

但是,如果我们从Mapper签名中删除PartFunc.apply(...)隐式参数,则一切正常。所以我不知道为什么以及Mapper如何影响Mapped

1 个答案:

答案 0 :(得分:3)

编译器抱怨Mapped,而实际问题是Mapper。我不知道为什么,但当Mappedpoly.type是抽象值或poly的构造函数参数时,为单例类型PartFunc获取poly似乎有问题。 }。

解决方案是让P <: Poly成为Actual并在创建PartFunc时将单身类型与import shapeless._ import ops.hlist.{Mapped, Mapper} import poly.~>> abstract class PartFunc[Actual <: HList, P <: Poly] { val poly: P def apply[L1 <: HList](l: L1)(implicit mapped: Mapped.Aux[Actual, TypedString, L1], mapper: Mapper[P, L1] ): mapper.Out = mapper(l) } def func[Actual <: HList] = new PartFunc[Actual, f.type] { val poly = f } 一起传递:

class PartFunc[Actual <: HList, P <: Poly](poly: P) {
  def apply[L1 <: HList](l: L1)(implicit
    mapped: Mapped.Aux[Actual, TypedString, L1],
    mapper: Mapper[P, L1]
  ): mapper.Out = mapper(l)
}

def func[Actual <: HList] = new PartFunc[Actual, f.type](f)

或者使用常规课程:

mapper(l)

请注意,我们现在必须写l map poly,因为Mapped[poly.type, L1]仍会查找func

我们现在可以致电func[ Int :: String :: HNil ](TypedString[Int]("42") :: TypedString[String]("hello") :: HNil) // String :: String :: HNil = 42 :: hello :: HNil

public static String  unicodeToString( char  charValue )
{
    Character   ch = new Character( charValue );

    return ch.toString();
}

我确信那些对Scala类型系统有更深入了解的人可以为我们提供更清晰的解释,并可能为这个问题提供更好的解决方案。