在方案中定义(指向)过程

时间:2016-05-10 10:45:57

标签: lambda scheme procedure

我是计划新手,并试图了解创建过程时$('li[data-id=45][data-ud=322 ]'); 的工作原理。更确切地说,以下两个声明之间的区别是:

define

有人可以提示(define name (procedure)) (define (name) (procedure)) 如何在引擎盖下工作吗?我知道在第一种情况下define创建一个指向过程的指针。第二个是没有参数define的过程的修剪版本,但指针(define (name arg) (procedure))name如何相互不同?

显然,(name)的使用取决于它的定义方式。

name

谢谢!

4 个答案:

答案 0 :(得分:3)

define形式是'语法糖':它只是一种更方便的语法。表达式

(define (foo x)
  (+ x 1))

根据定义等同于

(define foo
  (lambda (x)
    (+ x 1)))

也就是说,正如(define bar 1)设置bar等于 1(define foo (lambda ...))foo定义为等于 (lambda (x) (+ x 1)),这是一个过程(即函数),它在其单个参数中加1。

啊哈!这里的时刻意识到在Scheme(和其他Lisps)中,一个过程是一个值,其状态与1"hello"相同,因此可以分配给符号等为foo。 表达式(lambda ...)计算为过程类型的值。 直截了当,语法(define (foo ...) ...)应该是透明的。

(并没有想到'功能指针' - 这是一个C概念,只会混淆这里的事情。)

答案 1 :(得分:3)

这些都不是任何方式,形状或形式的指针。

define将名称绑定到当前环境中的值,而在Scheme中,过程是第一类值。

(define name (procedure))

name定义为现在调用procedure的结果的值。

(define (name) (procedure))

name定义为不带参数的过程,并在调用时返回不带参数调用procedure的结果。
第二种形式相当于

(define name (lambda () (procedure)))

示例(来自球拍 - current-seconds是自UTC时间1970年1月1日午夜起的秒数):

> (current-seconds)
1462879945
> (define name (current-seconds))
> name
1462879957

name是一个数字,而不是一个程序。

> (define (nameproc) (current-seconds))
> nameproc
#<procedure:nameproc>

nameproc是一个程序,而不是数字。

> (nameproc)
1462879980
> (nameproc)
1462879983

正如您所看到的,nameproc每次被调用时都会返回不同的值...

> name
1462879957
> name
1462879957

...但name是一个整数且不会改变。

答案 2 :(得分:2)

(define (proc) ...)只是(define proc (lambda () ...))的语法糖。

如果您熟悉命令式语言,define实际上是一种分配:

> (define proc 2)

&LT; =&GT; (ISH)

proc = 2;

您可以分配给符号的一件事是功能,如下所示:

> (define proc (lambda (x y) (+ x y)))
> (proc 1 2)
3

&LT; =&GT; (ISH)

>>> proc = lambda x, y: x + y
>>> proc(1, 2)
3

现在没有什么可以阻止你定义不带参数的函数:

> (define proc (lambda () (+ 1 1)))
> (proc)
2

指定proc 函数不带参数,并返回(+ 1 1)的值(即2)。这与<{1}}的不同,它直接将值分配给(define proc (+ 1 1))(实际上完全等同于proc)。

现在,可能让您感到困惑的是,由于编写(define proc 2)的工作量太大,因此Scheme实现通常会提供函数定义的“简写”版本:

lambda

所以> (define (proc <args>) <body>) <=> > (define proc (lambda <args> <body>)) 去了(define (proc) 2),而(define proc (lambda () 2))只是将(define proc 2)分配到2。符号可能通过指针绑定到值的事实是一个实现细节,只涉及您的解释器,并且应该与推理无关。

TL; DR:

proc

创建一个函数

(define (func) x) 

(define func x) 分配给x

答案 3 :(得分:0)

define可能是Scheme中最模糊的特殊形式,因为它在不同的范围和不同的第一个参数中用于不同的目的。这是:

符号与列表第一个参数之间的差异

define的基本用法是:

(define var <expression>)

它使用表达式var的结果定义变量<expression>

由于Scheme是一个LISP1程序(在其他一些语言中也称为函数)是用一个评估的lambda形式创建的,例如。 (lambda argument-list . body)您可以通过为define

分配一个名称来为该程序命名
(define add1 (lambda (n) (+ 1 n)))

对于命名程序,define有一种特殊的语法,其中definelambda表单被混合在一起。您可以将add1写为:

(define (add1 n) (+ 1 n))

这意味着完全一样,有些书籍不会将这最后一个版本暴露给用户,因为有两种方法可以解决这个问题,特别是如果你想要一个过程来返回一个过程。

顶级或词汇范围

当顶级值分配给全局范围时。这意味着所有程序都可以访问它,除非在本地范围内重新定义变量,查看使用中的代码和最高级别的代码。

如果define发生在程序的过程或语法糖中(letlet*letrecrec,{{1}然后,表单与过程顶部的lambda相同,它只存在于该过程和嵌套过程中。第二个letrec中的代码完成运行绑定消失:

letrec

这与:

相同
(define (test n)
  (define v (* 2 n))
  (define (add1 n) (+ 1 n))

  (add1 v))

letrec只是一个花哨的(define test (lambda (n) (letrec ((v (* 2 n)) (add1 (lambda (n) (+ 1 n))) (add1 v))))

let

当然(define test (lambda (n) (let ((v 'undefined) (add1 'undefined)) (let ((v1 (* 2 n)) (v2 (lambda (n) (+ 1 n)))) (set! v v1) (set! add1 v2)) (add1 v)))) 只是一个let,会立即应用:

lambda

(define test (lambda (n) ((lambda (v add1) ((lambda (v1 v2) (set! v v1) (set! add1 v2)) (* 2 n) (lambda (n) (+ 1 n))) (add1 v) ; can access n, v, and add1 but not v1, and v2 'undefined 'undefined))) 仅在名称和值之间进行绑定,其中值通常表示对象的地址(也称为指针)。相同的名称可以在不同的范围内具有不同的绑定,因此相同的变量名称并不总是指向同一个对象。这是一个例子:

define

此处,顶级(define lst '(1 2 3 4 5)) (define (last x) (define lst (cdr x)) (if (null? lst) (car lst) (last lst))) (last lst) ; ==> 5 始终为lst,而过程中的'(1 2 3 4 5)始终是参数lst的子列表之一。它们同时存在,但名称相同但都指向不同的值。在正文中,全局不可访问,因为它被具有相同名称的本地绑定所遮蔽。