scala - 隐式Mapper对隐式Mapped参数的奇怪影响

标签 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 映射器

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)

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

最佳答案

编译器提示Mapped而实际问题是 Mapper 。我不知道为什么,但获取 Mapped 似乎出了问题。对于单例类型poly.typepolyPartFunc 的抽象值或构造函数参数.

解决方案是制作 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):

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

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

关于scala - 隐式Mapper对隐式Mapped参数的奇怪影响,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38129113/

相关文章:

Scala:如何屏蔽字符串的前 N ​​个字符

haskell - Haskell 中的无限(最终周期性)HList

haskell - 基本 Haskell 单态/多态问题 (HList)

scala - Scala 的数据类型通用编程库

mongodb - 扩展 MongoDB Scala 驱动程序?

mysql - 将 Scala 和 Play-Slick 连接到 AWS MySQL

scala - Zipwith 产品实现与 Shapeless?

scala - Scala 中的类型安全通用案例类更新

scala - shapeless 将 case 类转换为 HList 并跳过所有选项字段

python - 使用 CheckList 和 Hlist 使用 Python 自动检查 Tix 中的子项