如果bound是抽象类型成员

时间:2018-03-10 18:16:54

标签: scala higher-kinded-types type-bounds scala-compiler abstract-type

我想定义一个由上限R和一个更高的kinded类型构造函数F[_]参数化的特征,它只接受R子类型的参数。我希望这个特性实现一个多态apply,可以将任何F[A]转换为Unit,前提是A <: R

此代码完美无缺:

import scala.language.higherKinds

// this is the trait with polymorphic `apply`
trait CoCone[R, F[_ <: R]] {
  def apply[A <: R](x: F[A]): Unit
}

// Example:
sealed trait Domain
class Dom1 extends Domain

class Fnctr[X <: Domain]

val c = new CoCone[Domain, Fnctr] {
  def apply[D <: Domain](x: Fnctr[D]): Unit = ()
}

(请参阅下面有关命名的说明)

现在,如果我通过声明它是某个模块的类型成员而在R上进行抽象,并在此模块中定义Fnctr[A <: R],如下所示:

import scala.language.higherKinds

trait CoCone[R, F[_ <: R]] {
  def apply[A <: R](x: F[A]): Unit
}

trait ModuleIntf {
  type AbstractDomain
  class Fnctr[X <: AbstractDomain]
}

// No mention of an actual concrete `Domain` up to
// this point. Now let's try to implement a concrete
// implementation of `ModuleIntf`:

sealed trait Domain
class Dom1 extends Domain

object ModuleImpl extends ModuleIntf {
  type AbstractDomain = Domain
  val c = new CoCone[Domain, Fnctr] { // error [1], error [2]
    def apply[D <: Domain](x: Fnctr[D]): Unit = ()
  }
}

一切都破了,我收到两条错误消息,我不知道如何解释:

[1] error: kinds of the type arguments (Domain,Main.$anon.ModuleImpl.Fnctr) do not 
conform to the expected kinds of the type parameters (type R,type F) in trait CoCone.
Main.$anon.ModuleImpl.Fnctr's type parameters do not match type F's expected parameters:
type X's bounds <: ModuleIntf.this.AbstractDomain are stricter than type _'s declared bounds <: R
      val c = new CoCone[Domain, Fnctr] {
          ^

[2] error: kinds of the type arguments (Domain,Main.$anon.ModuleImpl.Fnctr) do not 
conform to the expected kinds of the type parameters (type R,type F) in trait CoCone.
Main.$anon.ModuleImpl.Fnctr's type parameters do not match type F's expected parameters:
type X's bounds <: ModuleIntf.this.AbstractDomain are stricter than type _'s declared bounds <: R
      val c = new CoCone[Domain, Fnctr] {
              ^

我希望编译器能够识别ModuleImpl中的CoCone[Domain, Fnctr]内的所有三个Domain = AbstractDomain = R都是相同的类型。

我在这里遗漏了一些明显的东西,还是scalac 2.12.4的限制?如果这是一个限制,有人曾在任何地方报告过吗?

修改找到类似的内容:issue #10186。它是&#34;相同&#34;?不是&#34;相同&#34;?如果它是一个bug,我应该把它作为另一个测试用例吗?如果有人能够确认这不完全是我的错,和/或它确实与链接问题密切相关,那么这将是一个可接受的问题解决方案。

Edit2 :正如@Evgeny指出的那样,它不能完全是问题10186,因为它在不同的编译阶段(refchecks而不是typer)失败。

备注名称:我在这里称之为特征CoCone,类似于通常定义的~>,可以被认为是一种自然变换,排序。在某种程度上,CoCone[Dom, Fctr]类似于Fctr ~> Const_Unit,但F域仅限于Dom的子类型。实际上,CoCone[R, F]是一种形状F,它可以通过网络发送R的某些子类,但这并不重要,所以我已经抽象了名字远了。这个东西是一个相当常见的数学结构,没有什么太人为的,如果可以编译它会很好。

1 个答案:

答案 0 :(得分:3)

使用抽象类型成员的工作方法(尝试使用scalac 2.12.4):

import scala.language.higherKinds

trait CoCone[R, F[_ <: R]] {
  def apply[A <: R](x: F[A]): Unit
}

trait ModuleIntf {
  type AbstractDomain
  type X = ({type XX <: AbstractDomain; type XXX = XX with AbstractDomain})
  class Fnctr[X]
}

sealed trait Domain

case class Dom1() extends Domain

object ModuleImpl extends ModuleIntf {
  type AbstractDomain = Domain
  val f = new Fnctr[Dom1]()
  val c = new CoCone[Domain, Fnctr] {
    def apply[X](x: Fnctr[X]): Unit = ()
  }
  c(f)
}

想法取自issue #4745的评论。如果我不遗漏任何内容,这应该等同于原始的不可编辑方法。

正如我在refchecks#10186失败时发现当前问题编译在不同编译阶段(typer)失败,但无论如何,在#10186中提到了补丁,我试过它并修复了#10186本身,但仍然报告了当前的错误。

我会说编译,但我没有发现任何类似于当前问题的问题,所以,假设它还没有报告编译器错误。

@Andrey评论后更新。

是的,过于专注于获得可编辑版本并失去特质的上限。遗憾。

在更多潜入编译器内部后更新

我调试了一些验证更高级别的kinded类型(scala.reflect.internals.Kinds周围checkKindBoundsHK),看起来好像检查Fnctr边界时,绑定类型树中没有{{{ 1}}是AbstractDomain的别名。如果我将CoCone的第一个类型更改为Domain中的AbstractDomain,而不是在树中,我会看到它是object,但不是Domain边界。

顺便说一句,修复#10186尝试解决类似的问题,评估绑定参数Fnctr,因为我理解尝试获取具体类型,但是在我们的情况下,没有关于树中的具体类,返回asSeenFrom ..