【问题标题】:Type constraint for higher-kinded type in ScalaScala中高级类型的类型约束
【发布时间】: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


【解决方案1】:

你的尝试没有成功的原因是你有一种不匹配。 以下:

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(不用说,因为它不是具体类型,而是类型构造函数),所以您需要的隐式类型是@ 987654331@:

def functorLaw[A, F[_]] (fn :Functor[F])(implicit arb: Arbitrary[F[A]]) :Prop = forAll { (fa :F[A]) => true }

并且因为F[A]没有出现在类型参数列表中(有AF,但没有F[A]),“上下文绑定”语法糖不能用,我们只好离开它在使用显式(!)隐式参数列表。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-01-17
    • 2017-01-08
    • 1970-01-01
    • 2012-08-21
    • 1970-01-01
    • 2021-11-17
    • 2017-01-21
    相关资源
    最近更新 更多