类型必不可少?

Mar*_*urg 33 haskell

我曾经问过一个关于haskell初学者的问题,无论是使用data/newtype还是类型类.在我的特定情况下,事实证明不需要类型类.另外汤姆埃利斯给了我一个很好的建议,如有疑问该怎么办:

回答这个问题最简单的方法是:

    使用数据

我知道类型类可以使一些东西更漂亮,但AFIK并不多.同样令我印象的是,类型类主要用于脑干,更新的东西,新的类型类几乎没有被引入,一切都是用data/newtype完成的.

现在我想知道是否存在绝对需要类型类的情况,并且无法用data/newtype表示事物?

StackOverflow上回答类似的问题Gabriel Gonzales说

在以下情况下使用类型

    每种给定类型只有一个正确的行为

    类型类具有所有实例必须满足的关联方程(即"定律")

嗯..

或者是由于历史原因共存的类型和数据/新类型有些竞争的概念?

Edw*_*ETT 42

我认为类型类 Haskell的重要组成部分.

它们是Haskell的一部分,使其成为我所知道的最容易重构的语言,并且它们是您能够推断代码正确性的重要资产.

那么,我们来谈谈字典传递.

现在,任何类型的字典传递都是传统面向对象语言中事态的重大改进.我们知道如何在C++中使用vtable进行OOP.但是,vtable是OOP语言中"对象的一部分".融合与对象的虚函数表迫使你的代码,你有关于谁可以用新的功能扩展了核心类型,它真的只有谁有权将所有其他人要烤成的事之类的原作者刚性纪律形式他们的类型.这导致了"熔岩流代码"和各种其他设计反模式等.

如C#语言给你的扩展方法伪造新的东西破解的能力,并像其他语言让你委托一些工作为好,但他们是部分的解决方案Scala和多重继承语言"特征".

当你从他们操纵的物体中分离出vtable时,你会获得令人兴奋的力量.您现在可以将它们传递到任何您想要的地方,但是当然您需要为它们命名并谈论它们.模块/仿函数的ML规则和显式字典传递风格采用这种方法.

类型类别略有不同.我们依赖于给定类型的类型类实例的唯一性,并且在很大程度上,这个选择允许我们摆脱这种简单的核心数据类型.

为什么?

因为我们可以将字典的使用移动到使用站点,并且不必随身携带数据类型,我们可以依赖于这样的事实:当我们这样做时,没有任何关于代码行为的改变.

将代码机械转换为更复杂的手动传递的字典会丢失给定类型的这种字典的唯一性.将程序中的字典传递给程序中的不同点现在会导致程序具有极大的不同行为.您可能需要或可能不必记住数据类型构造的字典,如果您希望根据您的参数具有条件行为,那么您会感到懊恼.

对于简单的例子,Set您可以通过手动字典翻译逃脱.价格看起来不那么高.您必须在字典中烘焙,比如说,您Set在制作对象时如何排序,然后insert/ lookup,只会保留您的选择.这可能是您可以承担的成本.当你Set现在结合两个人的时候,当然,它是在空中命令你得到的.也许你走小,并将其插入到更大的,但随后的订货会威利愿意不愿意改变,所以不是你要好好说,左侧,并且始终将其插入正确,或文档此随意行为.为了"灵活性",您现在被迫进入次优的执行解决方案.

但这Set是一个微不足道的例子.在那里你可以为你正在使用的实例的类型加一个索引,只涉及一个类.当你想要更复杂的行为时会发生什么?我们用Haskell做的一件事就是使用monad变换器.现在你有很多情况下的漂浮-你没有一个好地方来存储他们所有,MonadReader,MonadWriter,MonadState,等可以适用于所有有条件..基于底层的单子.当你提升并换掉它时会发生什么,现在不同的东西可能适用也可能不适用?

为此做一个明确的词典是很多工作,没有一个存储它们的好地方,你要求用户采用全局程序转换来采用这种做法.

这些是类型类很容易实现的东西.

我相信你应该把它们用于一切吗?

不是由一个长镜头.

但我不能同意其他答复,他们对Haskell不重要.

Haskell是唯一提供它们的语言,它们至少对用这种语言思考的能力至关重要,并且是我考虑Haskell回家的重要原因.

我同意这里的一些事情,在有法律和选择明确的时候使用类型类.

但是我想挑战的,如果你不具备法律或如果选择的是不明确的,你可能没有足够的了解如何将问题域建模,并应寻求的东西,你适应它入类型类模具,甚至可能进入现有的抽象 - 当你终于找到解决方案时,你会发现你可以轻松地重复使用它.

  • 排序很好.任何一个特定的函数调用通常可以使用显式的"字典传递"样式正常工作.当你将生产与消费分开时,你不能总是侥幸逃脱.例如,在一个过程中构建一个Set然后在其中查找,然后插入更多,查找,合并等等.在该生命周期中,现在有几个地方可以选择导致非常不同语义的不同实例,一些它们的组合不健全,但没有一个被排除在外. (7认同)

luq*_*qui 30

在大多数情况下,类型是非必要的.任何类型类代码都可以机械地转换为字典传递样式.它们主要提供便利,有时是一定的便利(参见kmett的回答).

有时,类型类的单实例属性用于强制不变量.例如,您无法Data.Set安全地转换为字典传递样式,因为如果您使用两个不同的Ord字典插入两次,则可以使数据结构不变.当然,您仍然可以将任何工作代码转换为字典传递样式的工作代码,但是您无法将违反的代码视为非法.

法律是类词组的另一个重要文化方面.编译器不强制执行法律,但Haskell程序员期望类型类带来所有实例都满足的法则.这可以被利用来提供关于某些功能stonger保证.这种优势仅来自社区的惯例,而不是语言的正式属性.

  • 我想补充一点,如果没有类型类,我们就不会得到很好的语法糖,如`OverloadedStrings`,`Num`文字,`Monad`符号等等.这些对于在Haskell中工作并不是必不可少的,但它们确实使它变得不那么乏味. (7认同)
  • 我写的第一个正确的函数编程项目是用于Orwell中Z规范的快速原型设计.在字典传递样式中实现数学库确实非常烦人,有时候有更多的字典而不是实际的参数.切换到Gofer的类型类是一个巨大的缓解. (7认同)
  • 类型类提供的另一个好处是编译时优化.使用在编译时已知的单个类型类实例,可以将字典查找作为优化来执行.这可能看起来不是什么大问题,但如果你在内部循环中有类似"1 + 2*x - 12*x*x"的东西,那么每个循环就会有8个字典查找(包括文字).这加起来了.虽然有一些方法可以处理这种类型的优化,但它会自动发生类型类. (3认同)
  • 请注意,顺便说一下,法则不是类型类的唯一特征.您可以定义数据类型,并在文档中指定您放入的任何内容必须以与在类型类上指定法则相同的方式和效果满足某些属性. (2认同)

Cub*_*bic 5

要回答这部分问题:

"类型和数据/ newtype有点竞争的概念"

不是.Typeclasses是类型系统的扩展,它允许您对多态参数进行约束.像编程中的大多数东西一样,它们当然是语法糖[因此它们不是必不可少的,因为它们的使用不能被其他任何东西取代].这并不意味着它们是多余的.它只是意味着你可以使用其他语言设施来表达类似的东西,但是当你在它的时候你会失去一些清晰度.字典传递可以用于大多数相同的事情,但它在类型系统中最终不那么严格,因为它允许在运行时更改行为(这也是您使用字典传递而不是类型类的一个很好的示例).

无论你是否有类型类,数据和newtype仍然意味着完全相同的东西:在data新类型的数据结构的情况下引入一种新类型,并且在newtype作为类型安全变体的情况下引入type.