Functional programming 为什么lambda不是一个函数

Functional programming 为什么lambda不是一个函数,functional-programming,racket,Functional Programming,Racket,对于Racket编程语言,为什么lambda不被视为一个函数? 例如,它不能定义为这样的高阶函数。 (定义(我的lambda参数体) (lambda args body))lambda需要成为Scheme中的核心语言功能(如if,let,defineare),因为它正在构建一个so,因此需要管理一组已关闭的or(并以某种方式将它们的绑定放在闭包中) 例如: (define (translate d) (lambda (x) (+ d x))) 当您调用或计算(translate 3)时,d是3

对于Racket编程语言,为什么lambda不被视为一个函数? 例如,它不能定义为这样的高阶函数。
(定义(我的lambda参数体)

(lambda args body))

lambda
需要成为Scheme中的核心语言功能(如
if
let
define
are),因为它正在构建一个so,因此需要管理一组已关闭的or(并以某种方式将它们的绑定放在闭包中)

例如:

(define (translate d) (lambda (x) (+ d x)))
当您调用或计算
(translate 3)
时,
d
是3,因此动态构造的闭包应该记住
d
绑定到3。顺便说一句,您通常希望
(translate 3)
(translate 7)
的结果是两个不同的闭包,它们共享一些公共代码(但对
d
具有不同的绑定)

还可以阅读关于

解释所有细节需要一整本书。幸运的是,C.Queinnec写了这本书,所以请阅读他的书

(如果你读法语,你可以读那本书的最新法语)

另见

另请阅读wikipage关于


注:您可以,以及一些Lisp实现(特别是,可能)这样做,将
lambda
定义为一些-例如,它将扩展为以特定于实现的方式构建一些闭包(但
lambda
不能定义为函数)。

您的问题缺少一个关键区别:

  • lambda
    语法
  • 过程是
  • lambda形式是一种表达式形式,其值是一个过程。可以说,“lambda是否是函数”的问题是从一个类型错误开始的,因为lambda和过程不在同一个世界中

    但是让我们把它放在一边。看待这一点的另一种方式是根据评估规则来考虑它。用于将过程应用于参数的默认方案求值规则可以用如下伪代码表示:

    (define (eval-application expr env)
      (let ((values
            ;; Evaluate each subexpression in the same environment as the 
            ;; enclosing expression, and collect the result values. 
            (map (lambda (subexpr) (eval subexpr env)) 
                 expr)))
        ;; Apply the first value (which must be a procedure) to the
        ;; other ones in the results.
        (apply (car values) (cdr values))))
    
    ;;;
    ;;; Evaluate an expression of this form, returning a procedure:
    ;;;
    ;;;     (lambda <formals> <body> ...)
    ;;;
    (define (eval-lambda expr env)
      (let ((formals (second expr))
            (body (cddr expr)))
      ;; We don't evaluate `body` right away, we return a procedure.
      (lambda args
        ;; `formals` is never evaluated, since it's not really an 
        ;; expression on its own, but rather a subpart that cannot
        ;; be severed from its enclosing `lambda`.  Or if we want to
        ;; say it all fancy, the `formals` is *syncategorematic*...
        (let ((bindings (make-bindings formals args)))
          ;; When the procedure we return is called, *then* we evaluate 
          ;; the `body`--but in an extended environment that binds its
          ;; formal parameters to the arguments supplied in that call.
          (eval `(begin ,@body) (extend-environment env bindings))))))
    
    ;;;
    ;;; "Tie" each formal parameter of the procedure to the corresponding
    ;;; argument values supplied in a given call.  Returns the bindings
    ;;; as an association list.
    ;;;
    (define (make-bindings formals args)
      (cond ((symbol? formals)
             `((,formals . args)))
            ((pair? formals)
             `((,(car formals) . ,(car args))
               ,@(make-bindings (cdr formals) (cdr args))))))
    
    英文:

  • 在与“父表达式”相同的环境中计算所有子表达式
  • 将第一个结果(必须已对某个过程进行评估)应用于其余结果的列表
  • 现在,
    lambda
    不能成为过程的另一个原因是该求值规则不适用于
    lambda
    表达式。特别是,
    lambda
    的要点是不要立即评估它的身体!特别是,这正是困扰您的
    my lambda
    -如果您尝试以这种方式使用它:

    (my-lambda (x) (+ x x))
    
    在整个表达式出现的环境中,必须立即将中间的<代码>(x)< /> >作为调用一个名为“代码> x/CODE”的过程的调用。还必须立即评估
    (+x x)

    因此,
    lambda
    需要自己的评估规则。正如Basile的回答所指出的,这通常是作为Scheme系统实现中的原语实现的,但我们可以用伪代码来描述它,如下所示:

    (define (eval-application expr env)
      (let ((values
            ;; Evaluate each subexpression in the same environment as the 
            ;; enclosing expression, and collect the result values. 
            (map (lambda (subexpr) (eval subexpr env)) 
                 expr)))
        ;; Apply the first value (which must be a procedure) to the
        ;; other ones in the results.
        (apply (car values) (cdr values))))
    
    ;;;
    ;;; Evaluate an expression of this form, returning a procedure:
    ;;;
    ;;;     (lambda <formals> <body> ...)
    ;;;
    (define (eval-lambda expr env)
      (let ((formals (second expr))
            (body (cddr expr)))
      ;; We don't evaluate `body` right away, we return a procedure.
      (lambda args
        ;; `formals` is never evaluated, since it's not really an 
        ;; expression on its own, but rather a subpart that cannot
        ;; be severed from its enclosing `lambda`.  Or if we want to
        ;; say it all fancy, the `formals` is *syncategorematic*...
        (let ((bindings (make-bindings formals args)))
          ;; When the procedure we return is called, *then* we evaluate 
          ;; the `body`--but in an extended environment that binds its
          ;; formal parameters to the arguments supplied in that call.
          (eval `(begin ,@body) (extend-environment env bindings))))))
    
    ;;;
    ;;; "Tie" each formal parameter of the procedure to the corresponding
    ;;; argument values supplied in a given call.  Returns the bindings
    ;;; as an association list.
    ;;;
    (define (make-bindings formals args)
      (cond ((symbol? formals)
             `((,formals . args)))
            ((pair? formals)
             `((,(car formals) . ,(car args))
               ,@(make-bindings (cdr formals) (cdr args))))))
    
    ;;;
    ;;; 计算此表单的表达式,返回一个过程:
    ;;;
    ;;;     (拉姆达…)
    ;;;
    (定义(评估lambda expr env)
    (格式(第二次扩展))
    (正文(cddr expr)))
    我们不立即评估“body”,而是返回一个过程。
    (λargs)
    “formals”从未被评估过,因为它不是真正的
    表达本身,而是一个不能表达的子部分
    ;从它的封闭的“lambda”中分离出来。或者如果我们愿意的话
    ;说得天花乱坠,'formals'是“同步分类的”*。。。
    (let((绑定(使绑定形式为args)))
    ;当我们返回的过程被调用时,*然后*我们计算
    ;`body`--但是在一个扩展的环境中,绑定了它的
    ;调用中提供的参数的形式参数。
    (eval`(begin,@body)(扩展环境环境环境绑定‘‘‘‘‘‘‘)’)
    ;;;
    ;;; 将程序的每个形式参数与相应的
    ;;; 给定调用中提供的参数值。返回绑定
    ;;; 作为关联列表。
    ;;;
    (定义(使绑定形式为args)
    (条件((符号?形式)
    `(,formals.args)))
    ((成对形式)
    `(,(汽车形式),(汽车参数))
    ,@(制作绑定(cdr格式)(cdr参数()()())))
    
    为了理解这个伪代码,经过时间考验的事情是学习许多Scheme书籍中的一本,这些书籍演示了如何构建元循环解释器(用Scheme编写的Scheme解释器)。参见示例。

    在Scheme行话中,我们在整个标准报告中使用术语过程而不是函数。因此,由于这是关于scheme方言的,我将使用术语“过程”

    用标准的
    #之类的语言!球拍
    #!r6rs
    在使用新的词汇环境对主体进行求值之前,过程会先求值它们的参数。因此,由于
    if
    lambda
    比过程有特殊的求值规则,因此特殊形式和宏是引入新语法的方式

    用像
    #这样的惰性语言!lazy
    racket求值是根据需要进行的,因此许多在渴望语言中实现为宏/特殊形式的表单可以实现为过程。例如,您可以使用
    cond
    if
    作为一个过程,但不能使用
    if
    cond
    作为一个过程,因为这些术语本身将在访问时作为表单进行评估,而例如
    (cond(#t'真值))
    将失败,因为
    \t
    不是一个过程
    lambda
    与参数列表有类似的问题。

    函数调用(e0 e1 e2)的计算如下

  • 如果对e0求值,结果(希望)是一个函数f
  • 计算e1时,结果为值v1
  • 计算e2时,结果为值v2
  • f
    的函数体在