【发布时间】:2015-09-15 14:31:54
【问题描述】:
我正在尝试为 scala 中的 Functor 编写一个通用定律,其格式可以在 scalacheck 测试中用于许多 functor。该定律应该由构造函数 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 }
}
现在这可行,但并不理想。我需要为每个要运行的测试实例化该类,并且需要在那里提供任意FA 函数。当然,编译器需要这个函数,但是对于很多类型来说,它们存在应该这样做的隐含(例如 List[Int])。但是编译器将无法猜测这些隐式提供了任意FA,所以我需要自己实现这个,这是非常重复的。例如:
object IntListFunctorSpec extends FunctorSpec[Int, List] {
def arbitraryFA :Arbitrary[List[Int]] = Arbitrary(arbitrary[List[Int]])
...
}
我认为我不需要告诉 scalacheck 如何构建 int 列表。任何建议如何更优雅地做到这一点?
我尝试了其他关于高级类型边界的问题,但我无法确切知道如何使用它们,尽管它们听起来很接近。所以我想我会问。
【问题讨论】:
-
你试过
def functorLaw[A, F[_]] (fn :Functor[F])(implicit arb: Arbitrary[F[A]]) :Prop = forAll { (fa :F[A]) => true }吗? -
这很好用!我将代码缩短到原来的 25%。 Stackoverflow 永远不会让你失望 :)。您能否将其发布为答案以便我接受?还有一个问题:这个问题表明我不喜欢隐式(而且我真的不理解它们,并避免在我的程序中使用它们)。我们仍然没有以任何方式限制 F[_]。隐式是唯一的方法吗?
-
@SK2751 隐式类型类实例和隐式转换或隐式值作为配置等之间存在很大差异。无论好坏,Scala 对类型类的编码都是建立在隐式之上的,并试图避免它们同时使用像
Arbitrary这样的类型几乎肯定会适得其反。 -
@TravisBrown,你是绝对正确的,正如我的问题所证明的那样:)
标签: scala generics polymorphism scalacheck higher-kinded-types