繁体   English   中英

为什么smalltalk不是函数式编程语言?

[英]Why is smalltalk not a functional programming language?

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

需要考虑什么呢?

功能编程语言没有公认的定义。

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

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


我建议您阅读以下相关博客文章(以及下面的评论):

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

例如,Squeak的Point类有一个功能API:像1@1 translateBy: 1@1返回具有新状态的新点,而不是改变内部状态。 (这使得Point几乎不可变,因为改变对象内部状态的唯一方法是通过#instVarAt:等反射机制。)

在Smalltalk中使用高阶函数(如地图,滤镜,折叠等)是很正常的。 鉴于将这些内容融入Collections API,编写以功能性方式使用Collections的代码通常更容易。

很多人对“函数式编程语言”的定义如此之多,以至于“Foo a 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.

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

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

Smalltalk在大多数情况下可以表达使用面向对象编程范例创建的所有解决方案,但它无法原始地表达使用功能编程范例创建的许多解决方案。 这就是为什么我不认为它是一个FPL。 尽管不能原始地表达FPL可以提供的每个解决方案,但Smalltalk极其可扩展,您可以扩展它以表达FPL可以提供的所有解决方案。

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

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

通过命名函数,语言不会成为函数式语言 - 按照这个定义,C将是有用的! 更重要的是数学意义上的功能语义,结果仅取决于参数(特别是:没有副作用)。 通过这个定义,可以通过setter修改的对象与函数式编程风格相反。 但是,正如已经指出的那样,如果禁止副作用,偶数对象也可以用于函数样式(Rectangle示例)。 而且,顺便说一句。 在具有方法的对象和一组函数之间存在二元性,这些函数在私有状态的闭包中定义(有关详细信息,请参阅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)。 并且,因为设置! 是无功能的,打破了该计划的“功能”。

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

谢谢大家的所有答案。

我会在这里添加我的,这基本上是我(可能想念)对你的了解。

我认为调用OO或FP的标准是“东西”是使用该语言构建的; 不是这么简单或难以做到的,我的意思是,所使用的心理范式。

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

另一方面,如果样式或目标是使用其他工件,那么使用语言编写函数容易使其无法正常工作。 例如,Smalltalk使得编写匿名块或提供可插入的排序比较器非常容易,但这并不能使它成为任何功能,因为重点是使用对象并传递消息。 Blockclosures只是一种编码这些消息(不是函数)的机制,即使它们看起来就像它们是函数一样。

混乱来了,因为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需要使用函数作为构建块,而不是因为它使用对象。

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

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

但现在看看Smalltalk背后设计原则

[Smalltalk]将所需操作的名称以及任何参数作为消息发送到号码,同时理解接收者最了解如何执行所需操作。

这是否描述了您对功能编程的看法?

@Frank Shearar - 这也描述了Erlang。 Erlang现在不起作用吗?

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

需要考虑什么呢?

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

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

@Missing Faktor - 但在这个例子中是不是func一个命名函数?

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

没有 func是局部变量。 您已将匿名函数绑定到局部变量func

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

要查看差异,请查看此Erlang示例该示例显示匿名函数和命名函数。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM