我是 Scheme 的新手,只是对“定义”感到好奇。我见过这样的事情:
(define (square x) (* x x))
这是有道理的[函数名'square'输入参数'x']。但是,我找到了一些 90 年代的示例代码,并试图理解:
(define (play-loop-iter strat0 strat1 count history0 history1 limit) (~Code for function~)
除了函数名之外,所有这些输入参数都可以吗?
3 回答
简短的回答 - 是的,第一个符号之后的所有符号都是过程的参数(第一个是过程的名称)。也很高兴指出这一点:
(define (f x y)
(+ x y))
只是语法糖,两种形式是等价的:
(define f
(lambda (x y)
(+ x y)))
通常 - 您使用特殊形式将名称define
绑定到值,该值可以是任何可用的数据类型,包括特定的函数(lambdas)。
关于参数和过程定义的更多信息 - 很高兴知道该.
符号可用于定义具有可变数量参数的过程,例如:
(define (f . x) ; here `x` is a list with all the parameters
(apply + x))
(f 1 2 3 4 5) ; 0 or more parameters can be passed
=> 15
最后一个技巧define
(并非在所有解释器中都可用,但在 Racket 中有效)。定义返回过程的过程的快速快捷方式,如下所示:
(define (f x)
(lambda (y)
(+ x y)))
...这相当于这个,更短的语法:
(define ((f x) y)
(+ x y))
((f 1) 2)
=> 3
是的,strat0
通过limit
是play-loop-iter
函数的参数。
定义的一般形式是:
(define (desired-name-of-procedure item-1 item-2 item-3 ... item-n)
(; what to do with the items))
解释 , 行为的另一种方法define
是用“组合方式”和“抽象方式”来解释。
[A]简单的组合方式:
语法(item-1 item-2 item-3 ... ... item-n)
是 Scheme(和一般的 Lisp)提供的基本组合方式。
- 所有代码都是使用上述模式表示的列表
- 第一个(最左边的)项目始终被视为运算符
- 括号强制运算符的应用...最左边的项目需要接受后面的所有项目,作为参数
[B]抽象的手段很简单;一种命名事物的方法。
一个例子将展示这一切如何融入define
原始的想法......
define
示例——自下而上到达
考虑这个表达式:
(lambda (x y) (* x y))
用简单的英语,上面的表达式翻译为“创建一个接受两个参数并返回其乘积的值的无名过程”。请注意,这会生成一个无名过程。
更准确地说,在组合方式方面,Scheme 为我们提供了关键字lambda
作为创建用户定义过程的原始运算符。
最左边的项目 -- -- 被lambda
传递的项目(x y)
和(* x y)
作为参数,并且操作员应用程序规则强制lambda
对项目做一些事情。
lambda
内部定义的方式会导致它解析 list (x y)
,并将x
和y
作为参数传递给 list (* x y)
,这假定用户定义了遇到参数时lambda
要做什么。任何分配给并将按照规则处理的值。x
y
x
y
(* x y)
输入,抽象的手段......
假设我想在我的程序的几个地方引用这种类型的乘法,我可能会像这样调整上面的 lambda 表达式:
(define mul-two-things (lambda (x y) (* x y)))
define
将 mul-two-things 和 lambda 表达式作为参数,并将它们“绑定”在一起。现在 Scheme 知道mul-two-things
应该与一个过程相关联,以获取两个参数并返回它们的乘积。
碰巧,命名过程的要求非常普遍,并提供了如此强大的表达能力,Scheme 提供了一个看起来更简洁的快捷方式来完成它。
就像@oscar-lopez 所说,define
是Scheme 提供的“特殊形式”,用来命名事物。就 Scheme 的解释器而言,以下两个定义是相同的:
(define (mul-two-things x y) (* x y))
(define mul-two-things (lambda (x y) (* x y))