functional-programming - Scheme:返回另一个内部过程的过程

标签 functional-programming lisp scheme sicp

这是我相信你们中的许多人都熟悉的 SICP 书中的内容。这是本书中的一个早期示例,但我觉得一个非常重要的概念,我还无法理解。这里是:

(define (cons x y)
 (define (dispatch m)
   (cond ((= m 0) x)
         ((= m 1) y)
         (else (error "Argument not 0 or 1 - CONS" m))))
 dispatch)
(define (car z) (z 0))
(define (cdr z) (z 1))

所以在这里我明白carcdr正在cons 范围内定义,我知道他们映射了一些参数 z分别为 1 和 0(参数 z 是一些 cons )。但是假设我调用(cons 3 4) ...当我们立即进入这个内部过程 dispatch 时,如何评估参数 3 和 4这需要一些参数m我们还没有指定?而且,也许更重要的是,返回 ' dispatch 有什么意义? ?我根本不明白那部分。任何帮助表示赞赏,谢谢!

最佳答案

这是在 Scheme 中利用一等函数的最奇怪的(也可能是更精彩的)示例之一。 Little Schemer 中也有类似的东西,这是我第一次看到它的地方,我记得为它挠了好几天头。让我看看我是否可以用有意义的方式解释它,但如果不清楚,我很抱歉。

我假设你理解原语 cons , car , 和 cdr因为它们已经在 Scheme 中实现了,但只是提醒您:cons构造一对,car选择对的第一个组件并返回它,cdr选择第二个组件并返回它。以下是使用这些函数的简单示例:

> (cons 1 2)
(1 . 2)
> (car (cons 1 2))
1
> (cdr (cons 1 2))
2
cons 的版本, car , 和 cdr您粘贴的内容应该完全相同。我会试着告诉你怎么做。

首先,carcdr未在 cons 范围内定义.在您的代码片段中,所有三个( conscarcdr )都在顶层定义。函数dispatch是唯一在 cons 中定义的.

函数cons接受两个参数并返回一个参数的函数。重要的是这两个参数对内部函数 dispatch 可见。 ,这就是返回的内容。一会儿我会讲到的。

正如我在提醒中所说,cons构造一对。这个版本的cons应该做同样的事情,但它返回一个函数!没关系,我们并不真正关心这对是如何在内存中实现或布局的,只要我们能得到第一个和第二个组件。

所以有了这个新的基于函数的对,我们需要能够调用 car并将该对作为参数传递,并获取第一个组件。在 car 的定义中,此参数称为 z .如果您要使用这些新的 cons 执行我上面的相同 REPL session , car , 和 cdr函数,参数 zcar将绑定(bind)到基于函数的对,即 cons返回,即 dispatch .这很令人困惑,但只要仔细考虑一下,你就会明白。

基于car的实现, 似乎它采用一个参数的函数,并将其应用于数字 0 .所以它正在申请dispatch0 ,从 dispatch 的定义中可以看出,这就是我们想要的。 cond里面比较m01并返回 xy .在这种情况下,它返回 x ,这是 cons 的第一个参数,换句话说,该对的第一个组件!所以car选择第一个组件,就像在 Scheme 中的普通原语一样。

如果您对 cdr 遵循相同的逻辑,您会看到它的行为方式几乎相同,但将第二个参数返回到 cons , y ,这是该对的第二个分量。

有几件事可以帮助您更好地理解这一点。一种是回到第 1 章中对求值替换模型的描述。如果你仔细而细致地遵循这个替换模型,并在一些非常简单的例子中使用这些函数,你会发现它们是有效的。

另一种不那么乏味的方法是尝试使用 dispatch直接在 REPL 上运行。下面,变量 p被定义为引用 dispatch cons 返回的函数.
> (define p (cons 1 2))
#<function> ;; what the REPL prints here will be implementation specific
> (p 0)
1
> (p 1)
2

关于functional-programming - Scheme:返回另一个内部过程的过程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12496482/

相关文章:

lisp - 访问方案中高阶过程的输入

javascript - 逻辑 'and' 与 javascript 中的对象和值

android - 如何运行传递给模拟方法的 lambda 函数?

java - 如何通过从 Java 传递参数来运行 lisp 脚本

带有 slime-fancy 的 clojure 和 common lisp 的 emacs 设置 (slime-autodoc)

functional-programming - 将文本解析为 Racket/Scheme 中的树

functional-programming - 如何避免使用可变数据结构并使用更多功能方法?

java - 术语 : What do you call a function that does not change object state?

haskell - 无法将类型 `h' 与 `String' 匹配

java - 是否可以在 JScheme 中编写 Java 类?