调用函数和在纯函数式语言中实例化对象之间是否存在关系?

时间:2010-09-22 19:09:57

标签: language-agnostic functional-programming lisp immutability

想象一下一个简单的(组成的)语言,其函数如下:

function f(a, b) = c + 42
    where c = a * b

(说它是Lisp的一个子集,包括'defun'和'let'。)

还想象它包含看起来像的不可变对象:

struct s(a, b, c = a * b)

再次类比于Lisp(这次是一个超集),假设像这样的结构定义会生成以下函数:

make-s(a, b)
s-a(s)
s-b(s)
s-c(s)

现在,考虑到简单的设置,似乎很清楚,当您调用'f'或'make-s'时,幕后发生的事情之间存在很多相似之处。一旦在调用/实例化时间提供'a'和'b',就有足够的信息来计算'c'。

您可以考虑将struct实例化为类似于调用函数,然后存储生成的符号环境,以便在调用生成的访问器函数时供以后使用。或者你可以把一个函数评估为创建一个隐藏的结构,然后用它作为评估最终结果表达式的符号环境。

我的玩具模型是否过于简单,以至于没用?或者它实际上是一种有用的方式来思考真正的语言是如何工作的?是否有任何真正的语言/实现,没有CS背景但对编程语言感兴趣的人(即我)应该了解更多,以便探索这个概念?

感谢。

编辑:感谢目前为止的答案。为了详细说明,我想我想知道的是,如果有任何真正的语言,那么学习语言的人就会被告知,例如“你应该认为对象基本上是封闭的”。或者,如果有任何真正的语言实现,那么实例化对象并调用函数实际上共享一些常见的(非平凡的,即不仅仅是库调用)代码或数据结构。

我所做的类比,我知道其他人之前所做过的,在任何实际情况下,是否比单纯的类比更深入了?

4 个答案:

答案 0 :(得分:3)

你不能比lambda演算更纯粹:http://en.wikipedia.org/wiki/Lambda_calculus。 Lambda演算实际上是如此纯粹,它只有函数!

在lambda演算中实现一对的标准方法是这样的:

pair = fn a: fn b: fn x: x a b
first = fn a: fn b: a
second = fn a: fn b: b

所以pair a b,你可以称之为“struct”,实际上是一个函数(fn x: x a b)。但它是一种特殊类型的函数,称为闭包。闭包本质上是一个函数(fn x: x a b)加上所有“免费”变量的值(在这种情况下,ab)。

所以是的,实例化一个“struct”就像调用一个函数,但更重要的是,实际的“struct”本身就像一个特殊类型的函数(一个闭包)。

如果您考虑如何实现lambda演算解释器,您可以看到另一方面的对称性:您可以将闭包作为表达式加上包含所有自由变量值的结构。

很抱歉,如果这一切都很明显,你只想要一些现实世界的例子......

答案 1 :(得分:1)

对象和闭包之间存在关系。 http://people.csail.mit.edu/gregs/ll1-discuss-archive-html/msg03277.html

以下创建了一些可能称为函数的东西,而其他人可能会调用一个对象:
取自SICP(http://mitpress.mit.edu/sicp/full-text/book/book-Z-H-21.html

(define (make-account balance)
  (define (withdraw amount)
    (if (>= balance amount)
        (begin (set! balance (- balance amount))
               balance)
        "Insufficient funds"))
  (define (deposit amount)
    (set! balance (+ balance amount))
    balance)
  (define (dispatch m)
    (cond ((eq? m 'withdraw) withdraw)
          ((eq? m 'deposit) deposit)
          (else (error "Unknown request -- MAKE-ACCOUNT"
                       m))))
  dispatch)

答案 2 :(得分:1)

  

我的玩具模型是否过于简单,以至于没用?

基本上,是的。您的简化模型基本上归结为说这些操作中的每一个都涉及执行计算并将结果放在某处。但这很普遍,它涵盖了计算机所做的任何事情。如果你没有执行计算,你就不会做任何有用的事情。如果你没有将结果放在某个地方,那么你就无法完成任何工作,因为你无法得到结果。因此,对计算机执行任何有用的操作,从添加两个寄存器到获取网页,都可以建模为执行计算并将结果放在稍后可以访问的位置。

答案 3 :(得分:1)

fmake-s都是函数,但相似之处并不多。应用f调用函数并执行其代码;应用make-s会创建一个结构。

在大多数语言实现和模型化中,make-s是与f不同的对象:f是一个闭包,而make-s是一个构造函数(在函数中)语言和逻辑意义,它接近于面向对象的语言意义)。

如果您想以面向对象的方式思考,fmake-s都有一个apply方法,但它们对此方法的实现完全不同。

如果你想根据底层逻辑思考,fmake-s在samme类型构造函数(函数类型构造函数)上有类型构建,但它们以不同的方式构造,有不同的破坏规则(函数应用程序与构造函数应用程序)。

如果您想了解最后一段,我建议Benjamin C. Pierce Types and Programming Languages。结构在§11.8中讨论。