Functional programming 在Scheme中,我如何理解;(定义(f x.y)(cons x y))“;
我不熟悉Scheme,这里我遇到了点列表的麻烦,下面是一个示例:Functional programming 在Scheme中,我如何理解;(定义(f x.y)(cons x y))“;,functional-programming,scheme,lisp,Functional Programming,Scheme,Lisp,我不熟悉Scheme,这里我遇到了点列表的麻烦,下面是一个示例: (define (f x . y) (cons x y)) (定义(f x.y)(cons x y)) 当我输入:(f 1 2 3)时,结果是'(1 2 3)。是的,它返回一个列表,此时 x => 1 and y => '(2 3). x=>1和y=>”(23) 我的问题是,当f使用不固定长度的args时,解释器如何知道这一点呢?解释器知道f有一个名为x的参数,后跟参数列表y。因此,当它遇到对f的调用时,它会将第一
(define (f x . y) (cons x y))
(定义(f x.y)(cons x y))
当我输入:(f 1 2 3)
时,结果是'(1 2 3)
。是的,它返回一个列表,此时
x => 1 and y => '(2 3).
x=>1
和y=>”(23)
我的问题是,当
f
使用不固定长度的args时,解释器如何知道这一点呢?解释器知道f
有一个名为x
的参数,后跟参数列表y
。因此,当它遇到对f
的调用时,它会将第一个参数放入x
,将剩余的参数放入y,(f x.y)
语法意味着定义的第一个参数是一个“不正确的”列表(相当于从(cons'f(cons'x'y))得到的)
而不是来自(cons'f(cons'x(cons'y nil)))
。因此,当调用函数时,每件事都会依次绑定。首先,x绑定到1,然后列表的其余部分绑定到Arment列表的尾部。因为此时,它是一个符号,所以y绑定到’(2 3).在scheme中,形式参数前的点
表示
该过程将是一个列表,包含所有剩余参数。因此,正如您在帖子中正确显示的那样,y
过程中是一个列表,'(2 3)
。在f
x中,将其视为正常参数
(define (f x . y)
(display "y: ")
(display y) (newline))
(f 1 2 'this 'is 'a 'list)
y: (2 this is a list)
以下是Guile参考手册对此的说明:
(variable1…variablen.variablen+1)
如果在最后一个变量之前有一个空格分隔的句点,则该过程将接受n个或>多个变量,其中n是句点之前的形式参数数。句点之前必须至少有一个参数。前n个实际参数将存储到前n个形式参数和序列的新分配位置欧洲
剩余的实际参数将转换为一个列表,并存储到最后一个正式参数的位置。如果正好有n个实际参数,则为空列表
存储到最后一个形式参数的位置
我不熟悉这个计划,这里我遇到了点列表的麻烦,这里是一个
例如:
(define (f x . y) (cons x y))
当我输入:(F123)结果是“(1233)。是的,它返回一个
列表,此时
x => 1 and y => '(2 3).
我的问题是,当f取时,口译员如何知道这一点
args的未固定长度
如果说f
接受的参数数量不固定或任意,这是不正确的。它至少需要一个参数。如果您尝试调用(f)
,您将得到一个错误。理解这里发生的事情的关键可能是理解Lisps中的虚线对表示法。它在另一个堆栈溢出问题中进行了讨论,但简短的版本是每个列表都是由对构建的。单个对可以写成(car.cdr)
。例如,(cons 1 2)=>(1.2)
。像(1.2.3)
这样的列表实际上是一对,其cdr
是另一对,其cdr
是另一对,等等:(1.(2.3.()
)
。因为这很难阅读,我们通常在编写一个对链时除去最后一个点以外的所有点,如果最后一个cdr
是()
,我们省略了点和()
,所以
(1 . (2 . (3 . 4)) === (1 2 3 . 4)
(1 . (2 . (3 . ())) === (1 2 3)
请注意,虽然默认打印机不会以这种方式打印,但列表(1 2 3 4)
也可以通过以下方式写入:
(1 . (2 3 4)) === (1 2 . (3 4)) === (1 2 3 . (4))
虽然它不会以这种方式打印,但您可以编写它,系统会理解它。例如
> '(1 2 . (3 4))
(1 2 3 4)
这可能是理解lambda列表表示法的关键。当我们为函数编写lambda列表时,它表示一个函数,并且lambda列表会根据参数进行解构。因此,如果我们有以下lambda列表并使用它们来解构参数列表(1 2 3)
,我们会得到结果绑定:
lambda-list x y z
-------------------------------------
(x y z) 1 2 3
(x y . z) 1 2 (3)
(x . y) 1 (2 3) n/a
x (1 2 3) n/a n/a
最后一种情况可能会令人惊讶,但您可以测试所有这些情况是否真的按预期工作:
((lambda (x y z) (list x y z)) '(1 2 3)) => (1 2 3)
((lambda (x y . z) (list x y z)) '(1 2 3)) => (1 2 (3))
((lambda (x . y) (list x y)) '(1 2 3)) => (1 (2 3))
((lambda x (list x)) '(1 2 3)) => ((1 2 3))
最后一个有点简洁,因为这意味着如果它还不是语言的一部分,你可以:
(define (list . elements) elements)
解释器是否也知道args
1 2 3
将被解析为一个列表'(1 2 3)
?@kedebug解释器知道(cons 1'(2 3))
的计算结果为'(1 2 3)
如果你是这么问的。很抱歉,我的意思是f
需要1 2 3
,它可以是三个参数,但是它被解析成一个列表'(1 2 3)
。我很难理解这一点。@kedebug它没有被解析成'(1 2 3)
。你用(cons 1'(2 3))在过程的主体中创建这个列表
将其称为“点”比“句号”更合适。Cons单元格有时被称为“点对”。谢谢@ChrisJester Young它是固定的!谢谢,Joshua,你找到我了。你可以使用点符号来表示正确的列表('a.'))是一个正确的列表。cons单元格由两个指针组成。因此,在类似于So的参数列表中使用时,它是将cdr
指针的内容绑定到一个值的一种方式,而不是依次绑定每个car
的内容。