在 Scala 3(点)或 Scala 2 中,如何使依赖类型具有传递性?

问题描述 投票:0回答:1

这是一个简单的例子:

  { // dependent type in function
    def dep[B](a: Any, bs: Seq[B]): Seq[(a.type, B)] = {

      val result: Seq[(a.type, B)] = bs.map { b =>
        (a: a.type) -> (b: B)
      }
      result
    }

    val ss = dep(3, Seq("a"))

    val ss2: Seq[(3, String)] = ss
  }

它之所以有效,是因为

a.type
在调用站点自动解析为
3.type
,尽管
a
在定义站点甚至没有确定性路径。

到目前为止工作正常,但稍有改动,调用站点扩展将不再起作用:

  { // in case class
    class Dep[B](a: Any, bs: Seq[B]) {
      def result: Seq[(a.type, Any)] = {

        val result: Seq[(a.type, B)] = bs.map { b =>
          (a: a.type) -> (b: B)
        }
        result
      }
    }

    object ss extends Dep(3, Seq("a"))

    val ss2: Seq[(3, String)] = ss.result
  }

/*
Found:    Seq[((ss.a : Any), Any)]
Required: Seq[((3 : Int), String)]

Explanation
===========

Tree: ss.result
I tried to show that
  Seq[((ss.a : Any), Any)]
conforms to
  Seq[((3 : Int), String)]
but the comparison trace ended with `false`:
*/

由于

Dep
现在是类构造函数,调用站点将坚持其成员类型定义而不是调用站点类型。这造成了很多混乱并违反了构造函数原则,有没有办法增强编译器来统一这两种情况?

我能想到的最接近的是使用辅助构造函数,但它只会产生一些难以理解的编译错误:

  { // in case class, as auxiliary constructor
    case class Dep[A, B](a: A, bs: Seq[B]) {

      def this[B](a: Any, bs: Seq[B]) = this[a.type, B](a, bs)

      def result: Seq[(A, Any)] = {

        val result: Seq[(A, B)] = bs.map { b =>
          (a: A) -> (b: B)
        }
        result
      }
    }
  }

/*
None of the overloaded alternatives of constructor Dep in class Dep with types
 [A, B](): Dep[A, B]
 [A, B](a: A, bs: Seq[B]): Dep[A, B]
match arguments (Null)
*/
scala dependent-type type-systems scala-3 dotty
1个回答
0
投票

我认为构造函数不能有自己的类型参数(或构造不同类型的实例)。另一个问题是,即使您可以定义该构造函数,也会使其变得不明确(

new Dep(1, Seq("foo"))
与两者都匹配)。

出于同样的(后一个)原因,

apply
也不起作用。我能想到的最好的办法就是制作另一个“工厂方法”:

case class Dep[A, B](a: A, bs: Seq[B]) {
 def result = bs.map { a -> _ }
}

object Dep { 
  def narrow[B](a: Any, bs: Seq[B]): Dep[a.type, B] = new Dep(a, bs)
}

Dep.narrow(3, Seq("foo", "bar")).result

如果您愿意交换参数

case class Dep[A, B](bs: Seq[B], a: A)
或添加额外的虚拟参数来解决歧义,那么您可以使用
apply
:

case class Dep[A, B](a: A, bs: Seq[B], dummy: Int) {
 def result = bs.map { a -> _ }
}

object Dep { 
  def apply[B](a: Any, bs: Seq[B]): Dep[a.type, B] = new Dep(a, bs, 0)
}

Dep(3, Seq("foo", "bar")).result
© www.soinside.com 2019 - 2024. All rights reserved.