scheme获取列表中的最后一个元素



我对scheme和car、cdr等概念非常陌生。我有这个函数来返回列表的最后一个元素,但现在它只返回一个空列表。

(define (last mylist)
(if (list? mylist)
(if (null? mylist)
(if (null? (cdr mylist))
'()
(last (cdr mylist)) 
)
)        
)
)

《如何设计程序》一书通过为您提供具体而详细的设计方法来帮助您解决这个问题。第9.2节"非空列表"涵盖了这一特殊问题。大体上,以下是您需要遵循的步骤:

  • 为非空列表制定数据定义(或取自书本)
  • 为您的职能编写目的说明、签名和标题
  • 编写测试用例(您的测试用例将在此处帮助批量。(请记住,您不需要测试数据定义不允许的输入)
  • 添加与数据定义关联的模板(也出现在本书中)
  • 填写模板中的空白处以完成定义
  • 调试

仅凭缩进,很明显您是从另一种编程语言进入Scheme的

但是您也错误地使用了if——在Scheme中,不能有单个分支if语句。Scheme中根本没有语句,只有表达式if表达式将始终采用3个操作数(自变量)

  1. 谓词(条件)
  2. 结果(如果谓词为true会发生什么)
  3. 替代(谓词为false时会发生什么)

您的程序已关闭。只要稍微调整一下,就可以到达需要的位置——注意缩进是如何使查看if的3个操作数变得容易的。

(define (last mylist)
(if (null? mylist)
#f
(if (null? (cdr mylist))
(car mylist)
(last (cdr mylist)))))

最后,Scheme提供了cond,有助于防止条件序列中不必要的代码嵌套

(define (last mylist)
(cond ((null? mylist)
#f)
((null? (cdr mylist))
(car mylist))
(else
(last (cdr mylist)))))
(last '())
;; #f
(last '(1))
;; 1
(last '(1 2))
;; 2
(last '(1 2 3))
;; 3

除了这个答案的范围之外,还有(last '())的返回值#f——我认为在空列表上调用last应该与在空列表中调用car具有相同的效果。但我还是交给你吧。

如果(null? mylist)不成立,它是什么?非空列表。

非空列表可以有一个或多个元素。

有多少元素有这样的列表,它们的最后一个元素是它们的第一个?

关于这些名单的cdr,我们能说些什么呢?您应该使用它来提前停止递归。现在它一直持续到列表为空,但您需要提前停止。

(define (last mylist)
(if (list? mylist)
(if (null? mylist)
'()
;; {1}
(last (cdr mylist))
;;
)))

{1},您无条件地呼叫(last (cdr mylist))。但是,如果你已经到达了你的清单的末尾呢?如果只剩下一个元素怎么办?在这种情况下,您需要返回it作为结果。因此,将无条件代码替换为if表达式即可完成此操作。

当您询问问题(null? (cdr mylist))时,如果这是真的,您应该返回(car mylist)而不是'()。因为在这一点上它意味着CCD_ 18是一个单原子列表。

(define (last mylist)
(cond ((null? mylist) '())
((null? (cdr mylist)) (car mylist))
(else (last (cdr mylist)))))

您可以使用cond而不是if来避免嵌套条件,因为cond处理许多臂,而if通常用于一个条件只有两个选项的情况。

这本书小Schemer在帮助我想象Scheme项目中发生的事情方面做得最好。

我认为这最接近您的初始代码:

(define (last mylist)
(if (list? mylist)
(if (null? mylist)
'() ; input list is empty
(if (null? (cdr mylist))
(car mylist) ; list only has one remaining element so this is it
(last (cdr mylist)))) ; otherwise, recurse
#f)) ; input is not a list

使用if时,请确保始终填写truefalse分支。

相关内容

  • 没有找到相关文章

最新更新