这是一个来自EOPL的练习。过程(invert lst)获取lst,它是一个包含2个列表的列表,并返回一个列表,其中每个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-list的单个元素?此时继续执行下一个成员,如果当前成员不是2-列表,则用"List is not a 2-List“替换当前成员。
发布于 2011-02-19 06:36:53
EOPL语言为eopl:error过程提供了提前退出并显示错误消息的功能。这本书(第三版)的第15页介绍了这一点。
EOPL语言还包含来自标准方案的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))))发布于 2011-02-18 23:16:37
所以看起来你的invert版本实际上返回了一个不同拓扑的列表。如果您在'((1 2) (3 4))上执行(invert ...),您将返回'((2 . 1) (4 . 3)),它是一个conses列表,而不是列表。
我写了一个维护列表拓扑的invert版本,但它不是尾递归的,所以它在递归时将最终维护一个调用堆栈。
(define (invert lst)
(if (null? lst)
lst
(cons (list (cadar lst) (caar lst))
(invert (cdr lst)))))如果您想要一个模拟反转行为的版本,请在倒数第二行中用cons替换list。
发布于 2011-02-18 23:32:00
如果您希望它在失败时尽早退出,可以尝试call/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语言中的返回语句的方法。它还可以做更多的事情,因为您可以存储延续,或者将多个延续传递到一个函数中,并在成功和失败时调用不同的一个。
https://stackoverflow.com/questions/5042809
复制相似问题