FnToProduct 不与类型构造函数一起使用

FnToProduct not working with a Type Constructor

为什么这会按预期工作:

def method1[L <: HList, M <: HList, F, R](list: L)(builder: F)
           (implicit ev: Comapped.Aux[L, Seq, M],
           fntp: FnToProduct.Aux[F, M => R]) = println("asd")

method1(Seq("asd") :: HNil) { (s: String) =>
  6
}

但这不是吗?

def method2[L <: HList, M <: HList, F, R](list: L)(builder: F)
           (implicit ev: Comapped.Aux[L, Seq, M],
           fntp: FnToProduct.Aux[F, M => Seq[R]]) = println("asd")

method2(Seq("asd") :: HNil) { (s: String) =>
  Seq(6)
}

似乎在 return 类型中为 FnToProduct.Aux 添加类型构造函数会破坏它。

问题是,当编译器试图推断 method1 的类型参数时,它会毫无问题地找到 LMF ,但是当它到达 R 时,它无法判断 FnToProduct.Aux 的第二个参数是否具有与 M => Seq[R].

对齐的正确形状

我无法很好地解释为什么这种情况会发生在第二种情况而不是第一种情况下,但这是一个你会 运行 经常遇到的限制,并且有有几个解决方法。

第一个是将 AuxFnToProduct 完全分开。根据您的实际方法,这可能很好,但如果您需要明确引用 R,它就不会起作用。

第二种解决方法是让第二种类型参数的 return 类型被推断出来,然后要求提供证据证明它是 Seq:

import shapeless._, ops.function.FnToProduct, ops.hlist.Comapped

def method2[L <: HList, M <: HList, F, S, R](list: L)(builder: F)
  (implicit
    ev: Comapped.Aux[L, Seq, M],
    fntp: FnToProduct.Aux[F, M => S],
    s: S <:< Seq[R]
  ) = println("asd")

method2(Seq("asd") :: HNil) { (s: String) => Seq(6) }

这有点额外的语法噪音,但它确实有效。