为什么这次迭代这里会产生空列表呢?
Why is the empty list produced here in this iteration?
让我们用下面的函数来得到一对数字:
; (range 1 3) --> '(1 2 3)
(define (range a b)
(if (> a b) nil
(cons a (range (+ 1 a) b))))
; generate pair of two numbers with 1 <= i < j <= N
(define (get-pairs n)
(map (lambda (i)
(map (lambda (j) (list i j))
(range 1 (- i 1))))
(range 1 n)))
(get-pairs 2)
; (() ((2 1)))
(get-pairs 3)
(() ((2 1)) ((3 1) (3 2)))
为什么上面会产生 '()
作为输出的第一个元素?将其与 python 进行比较,我希望它只给出三对,例如:
>>> for i in range(1,3+1): # +1 because the range is n-1 in python
... for j in range(1,i-1+1):
... print (i,j)
...
(2, 1)
(3, 1)
(3, 2)
我想这可能与 i
为 1 时有关?
(map (lambda (j) (list 1 j)) '())
; ()
空列表的映射总是空列表只是Scheme中的一个恒等式吗?
当i
为1时,内映射结束(range 1 0)
,也就是自己定义的()
。由于 map
采用过程和值列表(或列表),依次将过程应用于列表中的每个值,并且 returns 是包含结果的列表,将任何过程映射到包含的列表没有 值将return 一个不包含任何值的列表。
为 map
创建一个简单的定义可能会有所帮助,看看它是如何工作的。请注意,此定义并不完整;它只需要一个列表参数:
(define (my-map proc xs)
(if (null? xs)
'()
(cons (proc (car xs))
(my-map proc (cdr xs)))))
此处,当输入列表为空时,没有要映射的值,因此 returned 为一个空列表。否则,过程 proc
应用于输入列表中的第一个值,并将结果用于映射到列表其余部分的结果。
一些观察:
首先,空列表在标准 Scheme 或 vanilla Racket 中均未由 nil
表示,您不应该使用它。在 Scheme 的早期,nil
被允许作为来自其他 lisp 的程序员的拐杖,但很长一段时间都不是这样了。我不认为它曾出现在任何 RnRS 标准中,但 nil
可能在某些特定实现中幸存下来,直到 R4RS (1991)。 SICP就是那个时代的。今天你应该使用 '()
来表示 Scheme 中的空列表文字,这样你的代码就可以 运行 在任何 Scheme 实现上。 Racket 的 #lang sicp
允许书中的代码直接成为 运行,但这不应该阻止您使用通用符号。请注意,Common Lisp 确实 使用 nil
作为自评估符号来表示空列表和布尔值 false。今天在 Scheme 中看到这个看起来不太对。
其次,在尝试理解 Scheme 代码时,您可能更容易误入歧途,而不是通过思考 Python 来获得智慧。在这种特殊情况下,map
是 迭代构造,但它与 for
循环不同。 for
循环通常用于副作用,但 map
用于转换列表。 Scheme 有一个 for-each
形式,它是 意味着 用于它的副作用,从这个意义上说更像是一个 for
循环。不过,上面发布的 Python 版本与 Scheme 版本完全不同。打印结果而不是 returning 列表中的结果。在Scheme代码中,当i
为1时,内部映射就结束了(range 1 0)
--> ()
。但是,在 Python 代码中,当 i
为 1 时,内部循环结束 range(1, 1)
,因此此 for
循环体不会执行,也不会打印任何内容。
最好仔细考虑您想要理解的 Scheme 代码,回到基本定义,而不是基于 Python 拼凑一个可能有未考虑的极端情况的模型。
让我们用下面的函数来得到一对数字:
; (range 1 3) --> '(1 2 3)
(define (range a b)
(if (> a b) nil
(cons a (range (+ 1 a) b))))
; generate pair of two numbers with 1 <= i < j <= N
(define (get-pairs n)
(map (lambda (i)
(map (lambda (j) (list i j))
(range 1 (- i 1))))
(range 1 n)))
(get-pairs 2)
; (() ((2 1)))
(get-pairs 3)
(() ((2 1)) ((3 1) (3 2)))
为什么上面会产生 '()
作为输出的第一个元素?将其与 python 进行比较,我希望它只给出三对,例如:
>>> for i in range(1,3+1): # +1 because the range is n-1 in python
... for j in range(1,i-1+1):
... print (i,j)
...
(2, 1)
(3, 1)
(3, 2)
我想这可能与 i
为 1 时有关?
(map (lambda (j) (list 1 j)) '())
; ()
空列表的映射总是空列表只是Scheme中的一个恒等式吗?
当i
为1时,内映射结束(range 1 0)
,也就是自己定义的()
。由于 map
采用过程和值列表(或列表),依次将过程应用于列表中的每个值,并且 returns 是包含结果的列表,将任何过程映射到包含的列表没有 值将return 一个不包含任何值的列表。
为 map
创建一个简单的定义可能会有所帮助,看看它是如何工作的。请注意,此定义并不完整;它只需要一个列表参数:
(define (my-map proc xs)
(if (null? xs)
'()
(cons (proc (car xs))
(my-map proc (cdr xs)))))
此处,当输入列表为空时,没有要映射的值,因此 returned 为一个空列表。否则,过程 proc
应用于输入列表中的第一个值,并将结果用于映射到列表其余部分的结果。
一些观察:
首先,空列表在标准 Scheme 或 vanilla Racket 中均未由 nil
表示,您不应该使用它。在 Scheme 的早期,nil
被允许作为来自其他 lisp 的程序员的拐杖,但很长一段时间都不是这样了。我不认为它曾出现在任何 RnRS 标准中,但 nil
可能在某些特定实现中幸存下来,直到 R4RS (1991)。 SICP就是那个时代的。今天你应该使用 '()
来表示 Scheme 中的空列表文字,这样你的代码就可以 运行 在任何 Scheme 实现上。 Racket 的 #lang sicp
允许书中的代码直接成为 运行,但这不应该阻止您使用通用符号。请注意,Common Lisp 确实 使用 nil
作为自评估符号来表示空列表和布尔值 false。今天在 Scheme 中看到这个看起来不太对。
其次,在尝试理解 Scheme 代码时,您可能更容易误入歧途,而不是通过思考 Python 来获得智慧。在这种特殊情况下,map
是 迭代构造,但它与 for
循环不同。 for
循环通常用于副作用,但 map
用于转换列表。 Scheme 有一个 for-each
形式,它是 意味着 用于它的副作用,从这个意义上说更像是一个 for
循环。不过,上面发布的 Python 版本与 Scheme 版本完全不同。打印结果而不是 returning 列表中的结果。在Scheme代码中,当i
为1时,内部映射就结束了(range 1 0)
--> ()
。但是,在 Python 代码中,当 i
为 1 时,内部循环结束 range(1, 1)
,因此此 for
循环体不会执行,也不会打印任何内容。
最好仔细考虑您想要理解的 Scheme 代码,回到基本定义,而不是基于 Python 拼凑一个可能有未考虑的极端情况的模型。