[英]Type constraint for higher-kinded type in Scala
我试图在scala中为Functors编写一个通用法则,我可以在scalacheck测试中为许多仿函数重用这种格式。 法律应该由构造函数F [_]和元素类型参数化,比如A.
理想情况下,我会写这样的东西:
def functorLaw[A, F[_] :Arbitrary] (fn :Functor[F]) :Prop = forAll { (fa :F[A]) => true }
(我使用true而不是法律机构,因为确切的计算对我的问题无关紧要)
然而,我能破解的最好的方法是将它包装在一个抽象类中,提供一个隐式生成任意F [A]值的抽象:
abstract class FunctorSpec[A :Arbitrary, F[_]] extends Properties("foo") {
implicit def arbitraryFA :Arbitrary[F[A]]
def functorLaw (fn :Functor[F]) :Prop = forAll { (fa :F[A]) => true }
}
现在这个有效,但它并不理想。 我需要为每个测试实例化我想要运行的类,并且需要在那里提供任意的ARM函数。 当然,编译器需要这个函数,但对于许多类型,它们存在应该这样做的含义(例如对于List [Int])。 然而编译器将无法猜测这些隐式提供任意FA,所以我需要自己实现,这是非常重复的。 例如:
object IntListFunctorSpec extends FunctorSpec[Int, List] {
def arbitraryFA :Arbitrary[List[Int]] = Arbitrary(arbitrary[List[Int]])
...
}
我认为我不应该告诉scalacheck如何构建int列表。 有什么建议如何更优雅地做到这一点?
我尝试了更高级别的类型边界的其他问题,我无法弄清楚如何使用它们,即使它们听起来很接近。 所以我想我会问。
你的尝试不起作用的原因是因为你有一种不匹配。 下列:
def functorLaw[A, F[_] :Arbitrary] (fn :Functor[F]) :Prop = forAll { (fa :F[A]) => true }
只是一个语法糖:
def functorLaw[A, F[_]] (fn :Functor[F])(implicit evidence: Arbitrary[F]) :Prop = forAll { (fa :F[A]) => true }
所以从本质上讲,问题是你的方法需要一个类型为Arbitrary[F]
的隐式值,其中F是一个高阶类型( F[_]
),但这没有意义,因为Arbitrary
没有采用更高阶的类型:
// T is a first order type, it has the kind *
// Simply put, it is not a type constructor
class Arbitrary[T]
为了让您的代码按原样编译(并且有意义), Arbitrary
必须声明如下:
// T is a type constructor, it has the kind * -> *
class Arbitrary[T[_]]
现在是如何解决它。 在你的情况下,你想要的实际任意值是F[A]
类型,而不是F
(这应该不用说,因为它不是具体的类型,而是一个类型构造函数),所以隐含的你需要的是Arbitrary[F[A]]
类型Arbitrary[F[A]]
:
def functorLaw[A, F[_]] (fn :Functor[F])(implicit arb: Arbitrary[F[A]]) :Prop = forAll { (fa :F[A]) => true }
并且因为F[A]
不出现在类型参数列表中(有A
和F
,而不是F[A]
),所以不能使用“上下文绑定”语法糖,我们不得不使用显式(!)隐式参数列表。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.