【问题标题】:Why is smalltalk not a functional programming language?为什么 smalltalk 不是函数式编程语言?
【发布时间】:2011-04-01 11:05:48
【问题描述】:

随着对函数式编程语言的重新兴趣,我看到了 Smalltalk 和 FPL 之间的一些相似之处,即闭包(Smalltalk 中的 BlockClosures) 然而,Smalltalk 不是 FPL?

需要什么来考虑它?

【问题讨论】:

  • 因为 Smalltalk 是面向对象语言的代言人?
  • 能够将函数用作一等对象并不能使语言“功能化”,正如能够编写过程使语言“过程化”一样。
  • @Gabe:有人会争辩说,仅此一个属性就足以让一种语言贴上“函数式编程语言”标签。
  • @CurtainDog:OO 和函数式不是相互排斥的范式。
  • @CurtainDog 这是一个不错的学术职位,但实际上它没有任何意义:我不是在谈论某人写的论文,我是在谈论 Smalltalkers 实际上是如何写的,这是一种非常实用的方式,使用对象。无副作用的方法,方法/闭包作为一流的实体(对象,就像 Common Lisp,另一种函数式编程语言)。鉴于 Smalltalk 对 Lisp 的巨大影响,这并不奇怪。

标签: programming-languages functional-programming oop smalltalk


【解决方案1】:

函数式编程语言没有公认的定义。

如果您将函数式语言定义为支持一流函数的语言,那么是的,Smalltalk *是*一种函数式语言。

如果您还考虑支持不变性、代数数据类型、模式匹配、部分应用等因素,那么不,Smalltalk *不是*一种函数式语言。


我鼓励您阅读以下相关博文(以及它们下面的 cmets):

【讨论】:

  • 确实,Smalltalk 几乎是一种函数式语言。 Smalltalk 有提供功能模式匹配的扩展,例如map.squeak.org/package/3772b420-ba02-4fbd-ae30-8eadfc323b7b。此外,Newspeak (newspeaklanguage.org) 是一种遵循 Self 和 Smalltalk 传统的编程语言,它支持将不变性作为其核心概念之一。
  • 这个定义不是让 C#、Javascript 和本世纪几乎所有的语言都能正常工作吗?
  • @Diego:正如我所说,“函数式编程语言”一词没有公认的定义。所以,根据第一个定义,是的。根据第二个定义,没有。
  • @Missing Faktor - Smalltalk 是否提供了一种声明命名函数的方法?
  • @AngelO'Sphere,我非常熟悉什么是一流的函数。 (Scala 和 Haskell 是我的主要语言。)无论如何,感谢您对这个术语的无偿解释。现在:在顶层拥有类与拥有一流的函数正交。 Scala、Smalltalk 和许多其他软件都具有这两个特征。还是您现在要使用“必须支持顶级函数定义”来修改您的定义?
【解决方案2】:

Smalltalk 可能不是一种“纯函数式语言”(不管它是什么)。然而,Smalltalk 的自然使用通常会产生函数式代码。 (我猜 Scala 人会称之为“对象功能”。)

例如,Squeak 的 Point 类有一个函数式 API:像 1@1 translateBy: 1@1 这样的方法会返回带有新状态的新 Point,而不是改变内部状态。 (这使得 Point 实际上是不可变的,因为改变对象内部状态的唯一方法是通过像 #instVarAt: 这样的反射机制。)

在 Smalltalk 中使用高阶函数(如地图、过滤器、折叠等)是很正常的。鉴于这些已融入 Collections API,编写以函数方式使用 Collections 的代码通常比不编写代码更容易。

很多人对“函数式编程语言”有太多定义,以至于“Foo 是一种 FPL”这个问题就像“Foo 是一种面向对象的语言”一样无用。

话虽如此,这是我的两分钱:函数式编程语言是一种自然并且惯用采用函数式技术的语言:一流的函数,避免可变状态、无副作用函数、高阶函数。

根据该描述,Smalltalk 是一种函数式编程语言。它将一阶函数称为“方法”或“块”,具体取决于它们是命名的还是匿名的。对象将状态存储在实例变量中。高阶函数只是将块作为参数的方法。

话虽如此,是的,您可以以非功能性方式编写 Smalltalk。它确实允许可变状态。这是否会阻止 Smalltalk 被称为函数式语言?如果是这样,这些语言都不是功能性的:Common Lisp、Erlang(通过进程字典共享状态、ets/dets)。

所以,简而言之,Smalltalk 是一个 FPL,因为:

  • 函数是一等实体(准确地说,是 Smalltalk 中的对象 - CompiledMethods 或 BlockClosures)。
  • Smalltalk 支持闭包(它称它们为块)。
  • Smalltalk 允许人们以一种自然、惯用的方式进行函数式编写。

并且Smalltalk 不是 FPL,因为:

  • 作为程序员,您必须确保您的数据结构(对象)是不可变的(通过让 setter/mutators 返回具有突变状态的对象的副本)。
  • 作为程序员,您必须确保您的方法(函数)没有副作用。

(一些 Smalltalks 显然支持不可变对象。我的经验仅限于 Squeak,它不支持 VM 级别的不可变性。)

编辑:除了通过在对象上定义方法外,我不理解 igouy 对命名函数定义的需求。但无论如何,我们开始吧:

Smalltalk at: #func put: [:x | x + 1].
func value: 1.

【讨论】:

  • >> Smalltalk 可能不是一种“纯函数式语言”(不管它是什么)
  • 在 Smalltalk 中,程序被组织成对象,但在函数式编程语言中,程序被组织成函数。我们在 OOP 和 FP 中构建程序的方式有一个很好理解的根本区别。有关示例,请参阅“综合面向对象和功能设计以促进重用”cs.brown.edu/~sk/Publications/Papers/Published/kff-synth-fp-oo
  • >> Squeak 的 Point 类有一个功能 API
  • @igouy:“组织成对象”并不是反对 Smalltalk 不是函数式语言的论据。请参阅 Common Lisp(尤其是 CLOS)。你说“对象”,我说“一组在同一种结构上工作的函数,在它们自己的命名空间中。”
  • @iguoy: >> Squeak 的 Point 类有一个功能性 API
【解决方案3】:

使用面向对象范式进行编程是通过将问题域实体识别和建模为对象来创建程序,然后使它们彼此协作以解决每个问题实例。 使用函数范式编程将问题建模为数学问题,并创建一个数学函数(通过组合其他函数),为每个问题实例计算问题解决方案。

在我看来,函数式编程语言是一种为使用函数式编程范式解决的问题提供解决方案的语言,该语言可以完全按照它的想法表达该解决方案。如果您需要“转换”解决方案的某些部分以使其适合语言可以表达的内容,那么它并不完全支持您过去思考解决方案的范式。

Smalltalk 在大多数情况下可以表达使用面向对象编程范式创建的所有解决方案,但它不能原始地表达使用函数式编程范式创建的许多解决方案。这就是为什么我不认为它是 FPL。 尽管最初无法表达 FPL 可以表达的所有解决方案,但 Smalltalk 具有极强的可扩展性,您可以将其扩展为能够表达 FPL 可以表达的所有解决方案。

【讨论】:

  • 你能举出一些 Smalltalk 不能“原始”表达的 FPL 事物的例子吗?
  • 尽管这是一个旧线程,但我对此处提供的 OO 定义持异议。 OO只是以实体交换消息和封装状态的形式来表达程序;直接将问题域“建模”为对象不会进入定义,而是 - IMO - 是一种工具,甚至是一种技巧。从这个意义上说,函数式程序可以被视为封装零状态并通过非常简单的消息(“应用”)进行交互的实体。这将使功能模型成为 OO 的子集。
【解决方案4】:

Smalltalk 是一种纯粹的面向对象语言,其中几乎所有代码基本上都是对象交换消息。函数式编程面向函数调用和函数之间的组合,以创建更复杂的行为(避免数据的状态,而不是对象在任何面向对象语言中具有的内部状态)。

【讨论】:

  • 嗯,“几乎所有”不是“1”或“a := b”等表达式。此外,函数的组合正是我所说的“smalltalkers 自然地在 Smalltalk 中编写函数”的意思。内部状态(实例变量的集合)与外部定义的结构相同。比如说一个CONS细胞。或者一个清单。或哈希图。 (重要的附带条件:你实际上已经以函数的方式在你的类上编写了方法,就像我给出的 Point 类示例一样。)
  • >> 内部状态(实例变量的集合)与外部定义的结构相同。
  • 呃。是的,你可以在 Smalltalk 中编写可变状态的东西。您也可以在 Common Lisp 中使用,这通常被认为是一种函数式编程语言。所以也许你对 FPL 的定义是“一种你只能在功能上编写的语言”?这排除了大多数人认为是功能性的一大堆语言:Common Lisp、Scheme、Erlang,......
  • @Frank Shearar - 我没有提到可变状态,所以大概您的评论是针对 Manuel 的?
  • @igouy 抱歉,不是我最清楚的 cmets。 “可变状态”针对的是 Manuel,但“您对 FPL 的定义”针对的是您。
【解决方案5】:

纯函数式语言通常具有不可变变量,使它们更像数学意义上的变量。

【讨论】:

  • 什么是数学意义上的变量不变性?例如,在等式 x^2 - 1 = 0 中,x 是不可变的吗?遍历 x ({-1, 1}) 的所有可能值是否使其可变?例如,Scala 中的以下代码: val results: Set[Double] = solve("x^2 - 1 = 0") 将 x 的所有可能值返回给结果,但函数 'solve' 可以对 an内部变量,因此在 Smalltalk 中任何实例都可以改变其内部状态来详细说明答案。任何人都可以在 Smalltalk 的一个对象中编写响应多个结果的代码。
【解决方案6】:

一种语言不会通过命名函数而成为函数式语言——根据这个定义,C 将是函数式的!更重要的是数学意义上的功能语义,结果仅取决于参数(特别是:没有副作用)。根据这个定义,可以由 setter 修改的对象与函数式编程风格相反。但是,正如已经指出的那样,如果您禁止副作用,即使对象也可以用于功能样式(矩形示例)。 而且,顺便说一句。具有方法的对象和在私有状态的闭包中定义的一组函数之间存在二元性(有关详细信息,请参阅 SICP)。他们可以互相模拟:

(def (make_foo initVal1 ... initValN)
   (let ((instVar1 initVal1) ... (instVarN initValN))
      (define (method1 args) ...)
      ...
      (define (methodN args) ...)
      (define (lookup selector)
          (cond ((eq? selector 'method1) method1)
             ...
             ((eq? selector 'methodN) methodN)
             (true doesNotUnderstandCode)))
      lookup)) ; returns the lookup function (provides "access into the closure") !

(defMacro (method1 receiver.args)
    ((receiver selector) args))

(define foo (make_foo 1 2 ...))
(method1 foo ...)

以上是“纯”功能对象的模拟,在语义上与很多 Smalltalk 代码相同!但是,要实现 setter 方法,您必须添加一个执行 (set!instVar newValue) 的方法。而且,因为设置!是非功能性的,破坏了方案的“功能性”。

总结:看语义,而不是来源,卢克!

【讨论】:

  • 你可以有setter,只要你的setter返回一个具有所需状态的新对象,而不是改变接收者。
  • >> 具有方法的对象和一组函数之间存在对偶性
  • >> 具有命名函数的语言不会成为函数式语言
  • Smalltalk 确实有命名函数。它们被称为方法。它们是绑定到类本地字典中的符号的 lambda。您还没有解释这与绑定到包中符号的 lambda 有何不同。
  • 冷静下来:让我们尝试定义一些我们都同意的共同基础:1)函数式风格是使用无副作用的函数; 2)函数式语言是一种函数式风格是最自然或首选的做事方式的语言。这使得 lisp 成为一种函数式语言,尽管它支持非函数式操作(例如 set!)和对象(clos 或类似的)。这也使得 Smalltalk 成为一种非函数式语言,尽管它也支持所有这些函数式的东西。 3) 你可以在 lisp 中编写 oo 风格,也可以在 smalltalk 中编写函数风格
【解决方案7】:

谢谢大家的回答。

我会在这里添加我的,这基本上是我(可能错过)对你的理解。

我认为调用 OO 或 FP 的标准是使用语言构建“东西”的方式;我的意思是,使用的心理范式不是做它的难易程度。

例如,如链接所示,在 Scala 中输入某些内容可能比在 OCaml 中更难,但这并不会降低 FPL(可能不完整或不纯,但绝对是功能性的);因为 Scala 的目标是使用函数作为主要构建块,而不是对象。

另一方面,如果风格或目的是使用其他工件,那么用一种语言编写函数并不容易。例如,Smalltalk 使得编写匿名块或提供可插入的排序比较器变得非常容易,但这根本不会使其具有任何功能,因为重点是使用对象和传递消息。闭包只是一种对这些消息(不是函数)进行编码的机制,即使它们看起来就像函数一样。

混乱来了,因为 OO 和 FP 是正交的(正如 Rahul 通过 twitter 所说),所以,它看起来像 Smalltalk 中的编码消息,看起来很像 Scala 中的匿名函数。但是做类似的事情并不会将一种范式的语言转换为另一种范式。

更糟糕的是,Scala 还使用了 OO 范式,以使主流(Java、C++、C#)程序员更容易实现跳跃,如果你看到,它比其他任何一个都取得了更大的成功FPL 做到了。当然,这要感谢 Java(恕我直言,如果 Clojure 取得任何成功,原因与 JVM 完全相同)

总结:一种编程语言可以根据它用来构建“事物”的范式进行分类。有些语言是纯粹的,例如 [Smalltalk:OO,Haskell:Functional,C:Procedural],或者是混合语言,例如 Scala 或多范式,例如 C++、Ruby、Python。

你可以用另一种语言编写一种风格,但这并不能使它成为那种风格的语言。就像用 Lisp 模拟对象并不能使它成为 OO 一样,也不能在 Java 中使用函数使其成为函数式。

要回答这个问题,要被认为是功能性的,Smalltalk 需要使用函数作为构建块,因为它使用对象而不是这样。

【讨论】:

  • 您的最后一行几乎说明了这一点。使用一种设计为多范式的语言(我认为这不会是 Ruby,也许不是 Python,C++ 太大了)可以很好地理解一种语言具有主导风格意味着什么。我发现使用 Mozart/Oz 非常有趣,因为将程序从一种风格改写为另一种风格是非常互动的——你可以从 OOP 开始将其改写为命令式风格,迭代地将破坏性赋值改写为声明式风格,然后并发逻辑编程让你发疯。
【解决方案8】:

我看到了两者之间的一些相似之处 Smalltalk 和 FPL,即闭包

还有一个更基本的相似之处 - 每条 Smalltalk 消息总是返回一个值。

但是现在看看Design Principles Behind Smalltalk

[Smalltalk] 发送名称 所需的操作,以及任何 参数,作为给数字的消息, 理解为 接收者最清楚如何执行 所需的操作。

这是否描述了您认为的函数式编程?

@Frank Shearar - 描述 Erlang 也。 Erlang 现在不能正常工作了吗?

Erlang 有点像一种嵌合体——顺序编程基于函数,而并发编程基于进程之间的消息传递。因此,Erlang 不是多范式或混合,因为其他语言允许使用不同的样式来实现相同的目的——它使用不同的样式来实现不同的目的。

【讨论】:

  • 这也描述了 Erlang。 Erlang 现在不能正常工作了吗?
  • 我之前的评论读起来有点刻薄。我并不是要(太)刻薄。上面还描述了后期绑定,我不认为它与 FP 不兼容。
  • @Frank Shearar >> Erlang 现在不能正常工作了吗?
  • @igouy:所以你的立场是,一种语言可以是 FPL 或 OOPL,但不能两者兼而有之?
  • @jgouy 我想念你的意思。我像骡子一样固执,或者你的意思是 Emacs 的多语言扩展可能会教给我一些东西?
【解决方案9】:

需要考虑什么 这样?

  • 一种声明函数的方式,而不是一种在类中声明方法的方式

  • 一种围绕函数而非对象构建程序的方法

@Missing Faktor - 但在这个例子中不是命名的 功能?

|func v|
func := [:x | x + 1].
v := func value: 5.

func 是一个局部变量。您已将 an anonymous function 绑定到局部变量 func

|func v|
func := [:x | x + 1].
func := 2.
v := func value: 5.

要查看区别,请查看this Erlang example,它同时显示了匿名函数和命名函数。

【讨论】:

  • 达到图灵等价性只是片刻的事。我的观点是,当一种语言不提供命名函数时,将其称为函数式编程语言是很愚蠢的。就像在不提供对象的情况下谈论 C 是一种 OO 编程语言一样愚蠢。
  • Smalltalk 中有命名函数,只是它们被称为方法。请解释一个方法如何不是一个命名函数。是的,一个方法访问状态。在 Point 的情况下,这些是不可访问的、不可变的实例变量。就像您提到的任何 FPL 都具有状态,以 ADT 或其他形式。
  • @Frank Shearar - 我们在 OOP 和 FP 中构建程序的方式有一个很好理解的根本区别 - 它们是对偶的。
  • 正如您从实践经验中知道的那样,在 Smalltalk 中工作既要找出动作(动词、函数、方法)的共性,又要提取结构(定义结构、元组) ,类)。 FP 强调动词而不是名词,而 OO 强调名词而不是动词。我看不出为什么一种语言不能同时支持这两种范式,并且我断言 Smalltalkers 确实在编写时同时练习了 OO 和 FP。您上面对 FPL 的定义包括 C,我不认为它是 OOPL 或 FPL。
  • 在此之前的一个小时你写道 - “@igouy,你还没有定义你对 FPL 的想法是什么......” - 但现在你说 - “你对上面 FPL 的定义...... 。”
猜你喜欢
  • 2019-06-04
  • 2010-09-28
  • 2017-01-14
  • 2013-07-23
  • 2011-02-09
  • 1970-01-01
  • 1970-01-01
  • 2011-04-27
  • 2011-04-02
相关资源
最近更新 更多