![]() |
1
67
ADT是关闭的,这使得编写总函数变得容易得多。这些函数总是为其类型的所有可能值生成一个结果,例如。
如果
在OO中,这不是一个问题,当您使用继承来扩展一个类型时,因为当您调用一个没有特定重载的函数时,它只能使用超类的实现。也就是说,你可以打电话
在Haskell中,当需要扩展类型时,通常使用封装和类型类。例如:
现在,
注意,有人在研究 extensible datatypes 但这绝对不是哈斯克尔的一部分。 |
![]() |
2
79
答案与代码易于扩展的方式有关,这是类和代数数据类型之间的紧张关系,菲尔·韦德勒称之为“表达式问题”:
因此,代数数据类型是闭合的,因为闭合类型很好地支持某些类型的程序演化。例如,如果您的数据类型定义了一种语言,那么在不使旧的编译器无效或更改数据的情况下,很容易添加新的编译器过程。 可能有“打开”的数据类型,但除非在仔细控制的情况下,类型检查变得困难。 托德·米尔斯坦做了一些 very beautiful work 在支持开放式代数类型和可扩展函数的语言设计中,所有这些都使用模块化类型检查器。我发现他的论文读起来很高兴。 |
![]() |
3
15
如果你写一个函数
然后你知道它永远不会产生运行时错误,因为你已经涵盖了所有的情况。只要类型是可扩展的,这就不再是真的了。在那些需要可扩展类型的情况下(它们比您想象的要少),规范的haskell解决方案是使用一个类型类。 |
![]() |
4
11
选中“打开数据类型和打开函数” http://lambda-the-ultimate.org/node/1453
|
![]() |
5
7
首先,与查理的答案相反,这不是函数式编程的固有问题。OCAML的概念是 open unions or polymorphic variants 这基本上是你想要的。 至于 为什么? 我相信这是哈斯克尔的选择,因为
所以如果你想
|
![]() |
6
6
在这个(公认是老问题)问题上有一些很好的答案,但我觉得我必须投入我的几分钱。
我相信,答案是开放式和给你的那种可扩展性是 不 总是一个优点,相应地,事实是 军队 这对你来说是个弱点。 封闭工会的优势在于 穷尽性 :如果您在编译时已经修复了所有的备选方案,那么您可以确定您的代码不会处理任何无法预料的情况。在许多问题域中,例如在语言的抽象语法树中,这是一个有价值的属性。如果您正在编写一个编译器,那么该语言的表达式就属于一个预定义的、封闭的子用例集合,您需要这样做。 不 希望人们能够在运行时添加编译器不理解的新子用例! 事实上,编译器ASTS是访问者模式的四个激励示例的经典组合之一,它是封闭和和和穷尽模式匹配的OOP对应物。反思一下这样一个事实是很有启发性的:OO程序员最终发明了一种模式来恢复已关闭的金额。 同样,程序和函数程序员也发明了模式来获得和的效果。最简单的是“函数记录”编码,它对应于OO接口。功能记录实际上是 调度表 . (注意,C程序员已经使用这种技术很久了!)诀窍是,给定类型的函数通常有大量可能的函数,通常无穷多。因此,如果您有一个字段是函数的记录类型,那么它可以很容易地支持一组天文数字般大或无限的替代项。而且,由于记录是在运行时创建的,并且可以根据运行时条件灵活地执行,所以替代方法是 晚绑定 . 我最后的评论是,在我看来,OO让太多人相信可扩展性是 晚绑定 (例如,在运行时向类型添加新的子实例的能力),而这通常不是真的。晚绑定是 一种技术 为了扩展性。另一种方法是 作文 用积木的固定词汇和组装规则构建复杂对象。词汇表和规则在理想情况下是很小的,但是它们的设计使它们具有丰富的交互作用,允许您构建非常复杂的东西。 函数式编程和ML/Haskell静态类型的风格,特别是长期以来强调组合而不是后期绑定。但在现实中,这两种技术都存在于两种范例中,并且应该在一个好的程序员的工具箱中。 同样值得注意的是,编程语言本身从根本上就是组合的例子。编程语言有一个有限的、希望是简单的语法,允许您组合它的元素来编写任何可能的程序。(事实上,这可以追溯到上面的编译器/访问者模式示例,并激励它。) |
![]() |
7
2
与面向对象的类相比,查看数据类型和类型类的另一种(或多或少)直观方法是: 一个班 福 在OO语言中,表示两种具体类型 福 以及所有人的阶级 福 -类型:直接或间接派生自 福 . 在OO语言中,您正好隐式地针对 福 -允许您“扩展”的类型 福 . |
![]() |
8
1
好吧,这里的“open”是指“can be derived from”而不是ruby和smalltalk意义上的“open”,您可以在运行时用新方法扩展类,对吗? 在任何情况下,注意两件事:第一,在大多数主要基于继承的OO语言中,有一种方法可以声明一个类来限制它被继承的能力。Java有“最后的”,在C++中有黑客。因此,它只是在其他OO语言中作为默认选项。 其次,你 可以 仍然创建一个使用闭合ADT的新类型,并添加其他方法或不同的实现。所以你不是真的受到限制。同样,它们在形式上似乎具有相同的力量;你可以用一种语言表达的东西可以用另一种语言表达。 实际上,函数式编程实际上是一种不同的范式(“模式”)。如果你期望它应该像一种OO语言,那么你会经常感到惊讶。 |
![]() |
Terio · Typescript:使用变量的值创建自定义类型 2 年前 |
![]() |
Kareem Adel · 创建函数类型(TypeScript接口) 2 年前 |
![]() |
MatÄj VondráÄek · 如何在c#方法中传递类型? 2 年前 |
![]() |
kreo · 为什么&[T]参数也接受&Vec? 6 年前 |
![]() |
Jiji · 将简单对象强制转换为简单的通用接口 6 年前 |