gpt4 book ai didi

scala - 根据参数值和函数参数类型推断通用父类(super class)型

转载 作者:行者123 更新时间:2023-12-04 12:38:03 25 4
gpt4 key购买 nike

是否应该在不需要显式类型定义的情况下编译以下 this ?

def prepList[B >: A](prefix: PlayList[B]) : PlayList[B] =
prefix.foldr(this: PlayList[B])((node, suffix) => suffix.prepNode(node))

在我看来,类型应该能够推断出来。这只是 Scala 编译器的一个限制,还是有类型理论的原因无法做到这一点?对于 Scala 类型推断器可以处理的内容,我还没有真正的感觉。

通过该方法工作:
  • B >: A根据定义
  • this有类型 PlayList[A] ,它是 PlayList[B] 的子类型自 B >: A并且播放列表在 A 中是协变的.
  • node有类型 B ,参数类型prefix .
  • 函数参数的第二个参数 ffoldrB 的第一个参数具有相同的类型(声明为 foldr ) .
  • 因此suffixthis 的类型相同,所以特别是一个 PlayList[A] .自 B >: A , suffix.prepNode()需要一个 B .

  • 我希望编译器看到 suffix.prepNode(node)哪里是合法的 node有类型 B .只有当我在调用 foldr 时明确指定类型时,它似乎才能做到这一点。或引用 this在那个调用中。

    有趣的是,如果我将函数参数的显式类型指定为 (node: B, suffix: PlayList[B]) ,方法调用的参数仍然会产生类型不匹配错误 suffix.prepNode(node) : "found: B, required: A"
    我正在使用 Scala 2.8 RC6。下面的完整示例,有问题的行是第 8 行。
    sealed abstract class PlayList[+A] {
    import PlayList._
    def foldr[B](b: B)(f: (A, B) => B): B

    def prepNode[B >: A](b: B): PlayList[B] = nel(b, this)
    def prepList[B >: A](prefix: PlayList[B]): PlayList[B] =
    // need to specify type here explicitly
    prefix.foldr(this: PlayList[B])((node, suffix) => suffix.prepNode(node))

    override def toString = foldr("")((node, string) => node + "::" + string)
    }

    object PlayList {
    def nil[A]: PlayList[A] = Nil
    def nel[A](head: A, tail: PlayList[A]): PlayList[A] = Nel(head, tail)
    def nel[A](as: A*): PlayList[A] = as.foldRight(nil[A])((a, l) => l.prepNode(a))
    }

    case object Nil extends PlayList[Nothing] {
    def foldr[B](b: B)(f: (Nothing, B) => B) = b
    }
    case class Nel[+A](head: A, tail: PlayList[A]) extends PlayList[A] {
    def foldr[B](b: B)(f: (A, B) => B) = f(head, tail.foldr(b)(f))
    }

    编辑:第二次尝试通过编译步骤进行推理
  • 为清晰起见重命名,foldr接受类型参数 (T)((U, T) => T) .我们试图推断类型的值 UT .
  • 第一个参数与foldr有关系和函数的第二个参数——它们是一样的,T . (对丹尼尔的部分回答。)
  • 我们作为这些参数传递的对象类型是 this: PlayList[A]suffix: PlayList[B]
  • 所以,由于 B >: A ,最具体的常见父类(super class)型是PlayList[B] ;因此我们有 T == PlayList[B] . 备注 我们不需要 U 之间的任何关系和 T推断出这一点。

  • 这是我卡住的地方:
  • 从编译错误信息来看,推理者显然认为node有类型 B (即 U == B )。
  • 我不明白它是如何得出 U == B 的结论的。不从 suffix 的类型参数推断它. (Scala 编译器能做到这一点吗?)
  • 如果推理的那一步发生了,那么 U == B ,我们就编译成功了。那么哪一步出错了呢?


  • 编辑 2:在重命名 foldr上面的参数类型我错过了 U == A根据定义,它是 PlayList 的类型参数类(class)。我认为这仍然与上述步骤一致,因为我们在 PlayList[B] 的实例上调用它。 .

    所以在调用站点, T == PlayList[B]作为一些东西中最不常见的父类(super class)型,以及 U == B根据 foldr 的定义在接收器上。这似乎足够简洁,可以缩小到几个选项:
  • 编译器无法解析这些多种类型并计算 B 的上限
  • 从返回类型获取的错误 PlayList[B]foldrprepNode 的参数类型(怀疑)
  • 最佳答案

    我不是类型专家,但这是我尝试推断时发生的情况。
    ((node, suffix) => suffix.prepNode(node))返回一些未知类型 PlayList[T] ,其中 T 扩展 A 。它作为参数传递给 foldr,foldr 返回传递给它的函数的类型(PlayList[T],其中 T 扩展 A)。这应该是某种类型 PlayList[B] .

    所以我的猜测是 this:PlayList[B]有必要表明 T 和 B 是相关的。

    可能您需要将 PlayList 设置为两种类型的参数 PlayList[+A, B >: A]因为您的 prepNode 和 propList 似乎适用于扩展 A 的相同类型?

    换句话说,您的原始类定义可能是这样定义的:

    def prepNode[T >: A](b: T): PlayList[T]
    def prepList[U >: A](prefix: PlayList[U]): PlayList[U]

    但是你在这两种情况下都使用了 B 并且编译器不知道 T 和 U 是相同的。

    编辑,您可以使用 -explaintypes 选项并查看编译器根据您获得的类型提示执行的操作。这是解释类型的输出并删除 :PlayList[B] (使用 2.8.0.RC1):
    $ scalac -explaintypes -d classes Infer.scala
    found : node.type (with underlying type B)
    required: A
    prefix.foldr(this)((node, suffix) => suffix.prepNode(node))
    ^
    node.type <: A?
    node.type <: Nothing?
    B <: Nothing?
    <notype> <: Nothing?
    false
    Any <: Nothing?
    <notype> <: Nothing?
    false
    false
    false
    false
    B <: A?
    B <: Nothing?
    <notype> <: Nothing?
    false
    Any <: Nothing?
    <notype> <: Nothing?
    false
    false
    false
    Any <: A?
    Any <: Nothing?
    <notype> <: Nothing?
    false
    false
    false
    false
    false

    希望这有助于阐明一些情况。可能是关于 scalac 何时可以推断以及何时不能推断会有帮助的问题。

    关于scala - 根据参数值和函数参数类型推断通用父类(super class)型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3131661/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com