这是EOPL的练习。 过程(反转lst)取lst,这是一个2列表的列表,并返回一个列表,每个列表都颠倒过来。
(define invert
(lambda (lst)
(cond((null? lst )
'())
((= 2 (rtn-len (car lst)))
( cons(swap-elem (car lst))
(invert (cdr lst))))
("List is not a 2-List"))))
;; Auxiliry Procedure swap-elements of 2 element list
(define swap-elem
(lambda (lst)
(cons (car (cdr lst))
(car lst))))
;; returns lengh of the list by calling
(define rtn-len
(lambda (lst)
(calc-len lst 0)))
;; calculate length of the list
(define calc-len
(lambda (lst n)
(if (null? lst)
n
(calc-len (cdr lst) (+ n 1)))))
这似乎工作但看起来非常冗长。这可以缩短或以更优雅的方式书写吗? 如何在任何单个元素中停止处理不是2列表? 如果当前成员不是2个列表,则执行前进到下一个成员并用“List is not 2-List”替换当前成员。
答案 0 :(得分:1)
因此,您的反转版本实际上会返回不同拓扑的列表。如果您在(invert ...)
上执行'((1 2) (3 4))
,则会返回'((2 . 1) (4 . 3))
,这是一个列表,而不是列表。
我编写了一个维护列表拓扑的反转版本,但它不是尾递归的,因此它会在递归时最终维护一个调用堆栈。
(define (invert lst)
(if (null? lst)
lst
(cons (list (cadar lst) (caar lst))
(invert (cdr lst)))))
如果您想要一个模仿您的反转行为的版本,请在倒数第二行将list
替换为cons
。
答案 1 :(得分:1)
如果您希望它在失败时提前退出,请尝试拨打/ cc。
(call-with-current-continuation
(lambda (exit)
(for-each (lambda (x)
(if (negative? x)
(exit x)))
'(54 0 37 -3 245 19))
#t))
===> -3
(取自http://www.schemers.org/Documents/Standards/R5RS/HTML/r5rs-Z-H-9.html#%_idx_566)
简而言之call-with-current-continuation
(或简称为call/cc
)将调用函数的点传递给函数,这提供了一种方法,可以在C语言中使用类似于return语句的方法。它还可以做更多的事情,因为你可以存储延续,或者将多个传递给一个函数,而另一个函数则被称为成功和失败。
答案 2 :(得分:1)
EOPL语言提供了eopl:error
过程,可以提前退出并显示错误消息。它在本书的第15页(第3版)中介绍。
EOPL语言还包括标准Scheme中的map
过程。虽然它可能没有在本书中使用,但您仍然可以使用它来获得比具有显式递归的解决方案更短的解决方案。您也可以使用Scheme的标准length
程序。
#lang eopl
(define invert
(lambda (lst)
(map swap-elem lst)))
;; Auxiliary Procedure swap-elements of 2 element list
(define swap-elem
(lambda (lst)
(if (= 2 (length lst))
(list (cadr lst)
(car lst))
(eopl:error 'swap-elem
"List ~s is not a 2-List~%" lst))))
答案 3 :(得分:0)
反向列表,其中包含任何数量或顺序的子列表。
{{1}}