问题描述
在小计划者一书中,我们发现此功能仅支持长度小于或等于 1 的列表:
In the book The little schemer, we find this function that only supports lists with length smaller than or equal to 1:
(((lambda (mk-length) ; A.
(mk-length mk-length))
(lambda (mk-length)
(lambda (l)
(cond
((null? l ) 0)
(else (add1 ((mk-length eternity ) (cdr l))))))))
'(1))
我想一步一步学习,并且想编写类似的函数,仅支持长度小于或等于 2 的列表.
I want to study step by step, and want to write the similar function that supports only lists of length smaller than or equal to 2.
请不要通过提供以下代码来回答这个问题:
Please, don't answer this question by offering code like:
(((lambda (mk-length) ; B.
(mk-length mk-length))
(lambda (mk-length)
(lambda (l)
(cond
((null? l) 0 )
(else (add1((mk-length mk-length) (cdr l))))))))
'(a b c d))
因为此功能支持任何长度.
because this function supports any length.
我已经知道如何编写这样的函数:
And I already know how to write function like this:
(((lambda (mk-length) ; C.
(mk-length
(mk-length (mk-length eternity))))
(lambda (length)
(lambda (l)
(cond
((null? l) 0)
(else (add1 (length (cdr l))))))))
'(1 2)) ;;
实现我的目标.但是,这段代码与第一个代码段相距不止一个步骤.
to achieve my goal. But this code is more than one step away from the first snippet.
也许我不应该更改:
(lambda (mk-length) ; D.
(mk-length mk-length)
推荐答案
TL; DR: (mk-length A)
(在cond
表单内部)计算 length
函数适用于长度为 0 的列表,并将使用(A A)
计算将用于尾部的 length
函数(即(cdr ...)
).
TL;DR: (mk-length A)
(inside the cond
form) calculates the length
function that works for lists of length 0 and will use (A A)
to calculate the length
function that will be used to work on the tail (i.e. the result of (cdr ...)
) of the argument list.
您的第一个代码段(;A.
)仅适用于长度为 0 和 1 的列表.要使其也适用于 2 ,请替换
Your first code snippet (;A.
) works for lists of length 0 and 1 only. To make it work for 2 also, replacing
(mk-length eternity) ; length≤1
使用
(mk-length ; (2) ; length≤2
(lambda (x) (mk-length eternity)))
有效.
(注意:(mk-length eternity)
本身会计算length≤0
,但整体功能变为length≤1
; 此是所有length≤i
注释所引用的内容.)
(NB: (mk-length eternity)
itself calculates length≤0
, but the overall function becomes length≤1
; this is what all the further length≤i
comments refer to.)
密切关注
(((lambda (mk-length)
(mk-length mk-length))
(lambda (mk-length) ; (1)
(lambda (l)
(cond
((null? l ) 0)
(else (add1 ((mk-length ; (2) ; length≤2
(lambda (x) (mk-length eternity)) )
(cdr l))))))))
'(1 2))
我们可以看到,在;(2)
处的(mk-length ...)
结果用于处理(cdr l)
,而在;(2)
处的 argument
至mk-length
将替换mk-length
在处理(cddr l)
时调用.
we can see that the result of (mk-length ...)
at ;(2)
is used to process (cdr l)
, while the argument
to mk-length
at ;(2)
will replace mk-length
in that call when processing the (cddr l)
.
如果使用(mk-length eternity)
(如您的第一个代码一样),则(cdr l)
可以正常处理,但((eternity eternity) (cddr l))
自然会失败.
If (mk-length eternity)
is used (as in your first code), (cdr l)
gets processed OK but ((eternity eternity) (cddr l))
naturally fails.
如果使用(mk-length (lambda (x) (mk-length eternity)))
,则(cdr l)
得到处理,然后((lambda (x) (mk-length eternity)) (lambda (x) (mk-length eternity))) = (mk-length eternity)
用于处理(cddr l)
,这也可以(因此,正确处理了长度 2 ),那么((eternity eternity) (cdddr l))
自然会失败(长度为 3 及以上).
If (mk-length (lambda (x) (mk-length eternity)))
is used, (cdr l)
gets processed OK and then ((lambda (x) (mk-length eternity)) (lambda (x) (mk-length eternity))) = (mk-length eternity)
is used to process (cddr l)
which is also OK (so, length 2 is handled correctly), and then ((eternity eternity) (cdddr l))
naturally fails (for lengths 3 and up).
因此可以处理最多三个元素的列表,
Thus to process the lists of up to three elements,
((mk-length ; (2) ; length≤3
(lambda (x) (mk-length
(lambda (x) (mk-length eternity)))) )
可以使用:
(define (eternity x) (- 1)) ; to get an error instead of looping
(((lambda (mk-length)
(mk-length mk-length))
(lambda (mk-length)
(lambda (l)
(cond
((null? l ) 0)
(else (add1 ((mk-length ; (2) ; length≤3
(lambda (x) (mk-length
(lambda (x) (mk-length eternity)))) )
(cdr l))))))))
'(1 2 3)) ; => 3
; ...........
; '(1 2 3 4)) ; => **error**
您正确地猜到了,这是使用方式中的过渡步骤
As you correctly surmised, this is the interim step on the way to using
(mk-length (lambda (x) (mk-length x))) ; (2) ; length≤∞
将列表中的下一个元素处理为
which turns, on the processing of the next element of the list into
((lambda (x) (mk-length x)) (lambda (x) (mk-length x)))
=
(mk-length (lambda (x) (mk-length x)))
,因此适用于每个列表,无论其长度如何.
and thus works for every list, whatever its length is.
通过eta转换,这只是(mk-length mk-length)
.
And by eta-conversion this is just (mk-length mk-length)
.
这篇关于Little Schemer:仅支持长度≤2的列表的写函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!