gpt4 book ai didi

generics - Scala:抽象类型与泛型

转载 作者:行者123 更新时间:2023-12-02 18:39:19 24 4
gpt4 key购买 nike

我在看 A Tour of Scala: Abstract Types .什么时候使用抽象类型更好?

例如,

abstract class Buffer {
type T
val element: T
}

而不是泛型,例如,
abstract class Buffer[T] {
val element: T
}

最佳答案

你对这个问题有一个很好的观点:

The Purpose of Scala's Type System
与 Martin Odersky 的对话,第三部分
作者:Bill Venners 和 Frank Sommers(2009 年 5 月 18 日)

更新(2009 年 10 月):以下内容实际上已在 Bill Venners 的这篇新文章中进行了说明:
Abstract Type Members versus Generic Type Parameters in Scala (见文末总结)

(这是第一次采访的相关摘录,2009 年 5 月,重点是我的)

一般原则

一直有两种抽象的概念:

  • 参数化和
  • 抽象成员。

  • 在 Java 中,您也有两者,但这取决于您抽象的内容。
    在 Java 中,您有抽象方法,但不能将方法作为参数传递。
    您没有抽象字段,但可以将值作为参数传递。
    同样,您没有抽象类型成员,但您可以将类型指定为参数。
    因此,在 Java 中,您也拥有所有这三个,但是对于可以将什么抽象原则用于什么类型的事物,这是有区别的。你可以争辩说这种区分是相当武断的。

    斯卡拉方式

    我们决定拥有 所有三种成员的相同构造原则 .
    因此,您可以拥有抽象字段和值参数。
    您可以将方法(或“函数”)作为参数传递,也可以对它们进行抽象。
    您可以将类型指定为参数,也可以对它们进行抽象。
    我们从概念上得到的是,我们可以根据另一个来建模一个。至少在原则上,我们可以将各种参数化表达为面向对象抽象的一种形式。所以在某种意义上你可以说 Scala 是一种更加正交和完整的语言。

    为什么?

    特别是什么 抽象类型为这些协方差问题提供了很好的解决方案 我们之前谈过。
    长期以来一直存在的一个标准问题是动物和食物问题。
    谜题是有一个类(class) Animal用一个方法, eat ,它吃一些食物。
    问题是如果我们子类化 Animal 并有一个类,例如 Cow,那么它们只会吃 Grass 而不是任意食物。例如,牛不能吃鱼。
    你想要的是能够说 Cow 有一种吃方法,它只吃草而不吃其他东西。
    实际上,您不能在 Java 中这样做,因为事实证明您可以构造不合理的情况,例如我之前谈到的将 Fruit 分配给 Apple 变量的问题。

    答案是 您将抽象类型添加到 Animal 类 .
    你说,我的新 Animal 类的类型是 SuitableFood ,我不知道。
    所以它是一个抽象类型。您没有提供该类型的实现。那么你有一个 eat只吃的方法 SuitableFood .
    然后在 Cow class 我会说,好吧,我有一个 Cow,它扩展了 class Animal ,并为 Cow type SuitableFood equals Grass .
    所以 抽象类型在我不知道的父类(super class)中提供了这种类型的概念,然后我稍后在子类中填写我知道的内容 .

    和参数化一样吗?

    确实可以。您可以使用它吃的食物种类来参数化类 Animal。
    但是 在实践中,当你用许多不同的东西来做这件事时,它会导致参数 爆炸式增长。 ,通常,更重要的是,在 参数边界 .
    在 1998 年的 ECOOP 上,Kim Bruce、Phil Wadler 和我在一篇论文中展示了 随着您不知道的事物数量的增加,典型的程序将呈二次方增长 .
    所以有很好的理由不做参数,而是拥有这些抽象成员,因为它们不会给你二次爆发。

    thatismatt在评论中问:

    Do you think the following is a fair summary:

    • Abstract Types are used in 'has-a' or 'uses-a' relationships (e.g. a Cow eats Grass)
    • where as generics are usually 'of' relationships (e.g. List of Ints)


    我不确定使用抽象类型或泛型之间的关系是否不同。
    不同的是:
  • 它们是如何使用的,以及
  • 如何管理参数边界。


  • 要了解 Martin 在谈到“参数爆炸,通常更重要的是,在 参数边界 中”,以及当抽象类型使用泛型建模时其随后的二次增长,您可以考虑论文“ Scalable Component Abstraction ”由... Martin Odersky 和 ​​Matthias Zenger 为 OOPSLA 2005 撰写,在 publications of the project Palcom 中引用(2007 年完成)。

    相关摘录

    定义

    Abstract type members provide a flexible way to abstract over concrete types of components.
    Abstract types can hide information about internals of a component, similar to their use in SML signatures. In an object-oriented framework where classes can be extended by inheritance, they may also be used as a flexible means of parameterization (often called family polymorphism, see this weblog entry for instance, and the paper written by Eric Ernst).



    (注意:家族多态性已被提议用于面向对象的语言,作为支持可重用但类型安全的相互递归类的解决方案。
    家族多态性的一个关键思想是家族的概念,用于对相互递归的类进行分组)

    有界类型抽象
    abstract class MaxCell extends AbsCell {
    type T <: Ordered { type O = T }
    def setMax(x: T) = if (get < x) set(x)
    }

    Here, the type declaration of T is constrained by an upper type bound which consists of a class name Ordered and a refinement { type O = T }.
    The upper bound restricts the specializations of T in subclasses to those subtypes of Ordered for which the type member O of equals T.
    Because of this constraint, the < method of class Ordered is guaranteed to be applicable to a receiver and an argument of type T.
    The example shows that the bounded type member may itself appear as part of the bound.
    (i.e. Scala supports F-bounded polymorphism)



    (注意,来自 Peter Canning、William Cook、Walter Hill、Walter Olthoff 的论文:
    Cardelli 和 Wegner 引入了有界量化,作为对给定类型的所有子类型统一操作的键入函数的一种手段。
    他们定义了一个简单的“对象”模型,并使用有界量化来对所有具有指定“属性”集的对象进行类型检查。
    面向对象语言的更现实的表示将允许作为 元素的对象。递归定义的类型 .
    在这种情况下,有界量化不再符合其预期目的。很容易找到对具有一组指定方法的所有对象有意义的函数,但不能在 Cardelli-Wegner 系统中输入。
    为了为面向对象语言中的类型化多态函数提供基础,我们引入了 F 有界量化)

    同一枚硬币的两个面

    编程语言中有两种主要的抽象形式:
  • 参数化和
  • 抽象成员。

  • 第一种形式通常用于函数式语言,而第二种形式通常用于面向对象的语言。

    传统上,Java 支持值的参数化和操作的成员抽象。
    带有泛型的最新 Java 5.0 也支持类型的参数化。

    在 Scala 中包含泛型的论据有两个方面:
  • 首先,手工编码成抽象类型并不是那么简单。除了不简洁外,还有名字的误区问题
    模拟类型参数的抽象类型名称之间的冲突。
  • 其次,泛型和抽象类型通常在 Scala 程序中扮演不同的角色。
  • 泛型 通常在需要时使用 类型实例化 , 而
  • 抽象类型通常在需要 时使用引用摘要
    从客户端代码输入
    .
    后者尤其出现在两种情况下:
  • 人们可能希望对客户端代码隐藏类型成员的确切定义,以获得一种从 SML 样式模块系统中已知的封装。
  • 或者人们可能想要在子类中协变地覆盖类型以获得家族多态性。

  • 在具有有界多态性的系统中,将抽象类型重写为泛型可能需要 quadratic expansion of type bounds .

    2009 年 10 月更新

    Abstract Type Members versus Generic Type Parameters in Scala (比尔·维纳斯)

    (强调我的)

    My observation so far about abstract type members is that they are primarily a better choice than generic type parameters when:

    • you want to let people mix in definitions of those types via traits.
    • you think the explicit mention of the type member name when it is being defined will help code readability.


    例子:

    if you want to pass three different fixture objects into tests, you'll be able to do so, but you'll need to specify three types, one for each parameter. Thus had I taken the type parameter approach, your suite classes could have ended up looking like this:


    // Type parameter version
    class MySuite extends FixtureSuite3[StringBuilder, ListBuffer, Stack] with MyHandyFixture {
    // ...
    }

    Whereas with the type member approach it will look like this:


    // Type member version
    class MySuite extends FixtureSuite3 with MyHandyFixture {
    // ...
    }

    One other minor difference between abstract type members and generic type parameters is that when a generic type parameter is specified, readers of the code do not see the name of the type parameter. Thus were someone to see this line of code:


    // Type parameter version
    class MySuite extends FixtureSuite[StringBuilder] with StringBuilderFixture {
    // ...
    }

    They wouldn't know what the name of the type parameter specified as StringBuilder was without looking it up. Whereas the name of the type parameter is right there in the code in the abstract type member approach:


    // Type member version
    class MySuite extends FixtureSuite with StringBuilderFixture {
    type FixtureParam = StringBuilder
    // ...
    }

    In the latter case, readers of the code could see that StringBuilder is the "fixture parameter" type.
    They still would need to figure out what "fixture parameter" meant, but they could at least get the name of the type without looking in the documentation.

    关于generics - Scala:抽象类型与泛型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1154571/

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