Recursion Little Schemer:编写只支持长度为≤;2.

Recursion Little Schemer:编写只支持长度为≤;2.,recursion,scheme,y-combinator,the-little-schemer,anonymous-recursion,Recursion,Scheme,Y Combinator,The Little Schemer,Anonymous Recursion,在《小模式者》一书中,我们发现这个函数只支持长度小于或等于1的列表: 我想一步一步地学习,并想编写一个类似的函数,它只支持长度小于或等于2的列表 请不要通过提供以下代码来回答此问题: (((lambda (mk-length) ; B. (mk-length mk-length)) (lambda (mk-length) (lambda (l) (cond

在《小模式者》一书中,我们发现这个函数只支持长度小于或等于1的列表:

我想一步一步地学习,并想编写一个类似的函数,它只支持长度小于或等于2的列表

请不要通过提供以下代码来回答此问题:

(((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))
因为这个函数支持任何长度

我已经知道如何编写这样的函数:

(((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)) ;;
为了实现我的目标。但这段代码与第一个代码片段相差一步多

也许,我不应该改变:

(lambda (mk-length)                                     ; D.
      (mk-length mk-length)
Lisp中的列表(Scheme、Common Lisp等)由cons单元格和特殊(空列表)组成。无论何时,只要你有一个列表,它是:

  • 空列表()
  • cons单元(也称为对),其中对的car是列表的第一个元素,对的cdr是列表的其余部分
因为有两种类型的列表,列表上的递归算法通常只回答两个问题:

  • 空列表的结果是什么
  • 列表其余部分的结果是什么?如何将其转化为整个列表的结果
对于长度,这意味着:

  • 空列表的长度为0
  • 当列表其余部分的长度为n时,整个列表的长度为n+1
《小阴谋家》中介绍的解决方案类型首先开发了一个解决方案,该解决方案回答了第一种情况,这意味着它适用于长度为≤0一旦您有了一个处理这两种情况的解决方案(正确),您就有了一个适用于任意长度列表的解决方案。没有真正的增量解决方案可以将函数扩展到长度列表≤二,

我想你可以这样做:

 (((lambda (mk-length)
      (mk-length mk-length))
  (lambda (mk-length)
      (lambda (l)
          (cond
              ((null? l ) 0)
              (else 1)))))
这对于长度为0的列表和长度为1的列表都有效,对于所有其他列表都不正确,但对于所有其他列表都返回1。除非你改变递归的结构,我认为这是你能做的最好的了。如果您愿意更改递归的结构,可以执行以下操作:

但你真的不应该采用这种方法,因为现在你在三种不同的情况下处理列表,而不是两种,这(几乎)永远都不是你想要做的

Python的翻译 这种想法可以用python或其他过程语言重写吗?仍然很难想象递归中自动创建的乐趣

同样的原理也适用于Python或任何支持高阶函数的语言。Python中更惯用的做法是在本地定义函数,然后调用它,而不是直接调用lambda表达式,因此这对您来说可能更具可读性:

def长度(l):
def驱动程序(递归):
“返回调用自身的'recurse'的结果。”
返回递归(recurse);
def ZeroForemptylStorelOnePlusResult(递归):
“”“返回一个函数,如果其输入为
空列表,否则返回1加上任何调用
`recurse(recurse)`返回列表的尾部。”“”
def长度(l):
“”“如果l是空列表,则返回0,加1
“(recurse(recurse))(l)”的结果为“否则”
如果l=[]:
返回0;
其他:
_,*rest=l
返回1+(递归(递归))(其余)
返回长度
返回(驱动程序(ZeroForeMptylStorelOnePlusRecreat))(l)

TL;DR:
(mk length A)
(在
cond
表单中)计算长度为0的列表的
长度
函数,并将使用
(A)
计算用于参数列表尾部的
长度
函数(即
(cdr…
)的结果


您的第一个代码段(
;A.
)仅适用于长度为0和1的列表。要使其也适用于2,请更换

                               (mk-length eternity)               ; length≤1
我们可以看到
(mk length…
处的结果;(2) 
用于处理
(cdr l)
,而
参数
用于
处的
mk length
;(2) 处理
(cddr l)
时,
将替换该调用中的
mk length

如果使用了
(mk length-eventhesis)
(与第一个代码一样),
(cdr l)
处理正常,但
((eventhesis-eventhesis)(cddr l))
自然会失败

如果使用了
(mk length(lambda(x)(mk length externature))
(cdr l)
处理正常,然后
((lambda(x)(mk length externature))(lambda(x)(mk length externature))=(mk length externature)
用于处理
(cddr l)
,这也是正常的(因此,长度2处理正确),然后
((永恒)(cdddr l))
自然失效(长度为3及以上)

因此,要处理多达三个元素的列表

                              ((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**
正如您正确猜测的,这是使用

                     (mk-length (lambda (x) (mk-length x)))   ; (2)       ; length≤∞
(mk长度(λ(x)(mk长度x));(2);长度≤∞
在处理列表的下一个元素时

                     ((lambda (x) (mk-length x)) (lambda (x) (mk-length x)))
    =
                     (mk-length (lambda (x) (mk-length x)))
((λ(x)(mk长度x))(λ(x)(mk长度x)))
=
(mk长度(λ(x)(mk长度x)))
因此,无论列表的长度如何,它都适用于每个列表


通过eta转换,这只是
(mk length mk length)

问题到底是什么?此外,您可能会在答案(或链接问题)中找到答案收件人:。我还不会将其标记为重复,因为我不确定您在这里要求的是什么。我的意思是,请执行与我粘贴到此处的第三个代码相同的操作。但应该来自第1个代码的想法。哪一个是
     (((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))
                              ((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**
                     (mk-length (lambda (x) (mk-length x)))   ; (2)       ; length≤∞
                     ((lambda (x) (mk-length x)) (lambda (x) (mk-length x)))
    =
                     (mk-length (lambda (x) (mk-length x)))