5

我想定义一个由上限R和更高种类的类型构造函数参数化的特征,该构造函数F[_]只接受R. 我希望这个 trait 实现一个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

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

编辑发现类似的东西:问题#10186。是“一样的”吗?不一样”?如果它是一个错误,我应该将它作为另一个测试用例提出吗?如果有人可以确认这不完全是我的错,和/或它确实与相关问题密切相关,那将是问题的可接受解决方案。

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


关于名称的备注:我在CoCone这里将特征称为特征,类似于通常定义~>的可以被视为自然转换的定义。在某种程度上,CoCone[Dom, Fctr]类似于Fctr ~> Const_Unit,但域F仅限于 的子类型Dom。实际上,它是可以通过网络发送某些子类CoCone[R, F]的形状的东西,但这并不重要,所以我已经抽象了名称。这东西是一个比较普通的数学结构,没什么做作的,如果能编译出来就好了。FR

4

1 回答 1

5

使用抽象类型成员的工作方法(尝试使用 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的评论。如果我没有遗漏任何东西,这应该等同于原始的不可编译方法。

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

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

在@Andrey 评论后更新。

是的,太专注于获得可编译的版本并且失去了特质的上限。对不起。

在深入了解编译器内部后更新

我调试了一些验证更高种类的类型(scala.reflect.internals.Kindsaround checkKindBoundsHK),看起来在检查Fnctr边界时,绑定类型树中没有信息AbstractDomainDomain. 如果我将 CoCone 第一种类型更改为AbstractDomainin object,那么无论如何在树中我看到它是Domain,但不是Fnctr边界。

顺便说一句,修复#10186试图解决类似的问题,评估绑定参数asSeenFrom,据我所知,试图获取具体类型,但在我们的例子中,一旦树中没有关于具体类的内容,AbstractDomain就会返回..

于 2018-03-12T12:51:37.853 回答