簡體   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