在课堂上,我们使用以下球拍结构为编造语言(lanG)编写了一个解释器。
(struct const (n))
(struct bool (b))
(struct join (e1 e2))
(struct if-then-else (b e1 e2))
(struct negate (e))
(struct add (e1 e2))
(struct multiply (e1 e2))
(struct head (e)) ;returns the head of the list
(struct tail (e)) ;returns the tail of the list
(struct biggerThan (e1 e2))
这种语言的宏被定义为球拍功能。一个简单的例子是:
(define (threeTimes x)
(add x (add x x)))
使用它看起来像:
(lanG (threeTimes (const 3)))
会产生答案:
(const 9)
现在我的问题。在考试中有一个任务,我们必须写一个宏sumAtEvenAndOdd,它将汇总一组lanG常数,
使用join结构生成并返回一对由偶数位置的元素和元素之和组成的值
在奇数位置。
此类列表的一个示例是:
(join (const 3) (join (const 2) (const 5))) ;lanG list with no null at the end
结果将是:
(join (const 2) (const 8))
我尝试通过将列表转换为球拍列表,用元素划分位置,从列表中过滤奇数或偶数元素来解决此问题, 并使用这些列表的总和产生该对。这有效,但我过于复杂。教授说解决方案大约有5行。
我事先感谢你的帮助。
答案 0 :(得分:1)
我假设还有谓词来标识const
和join
- 我们称之为const?
和join?
。
假设我们有一个函数来添加列表中的所有其他项,sumAtEvenAndOdd
可能如下所示:
(define (sumAtEvenAndOdd xs)
(join (sumEveryOther (tail xs)) (sumEveryOther xs)))
然后sumEveryOther
可以像这样实现:
(define (sumEveryOther x)
(if-then-else (const? x)
x
(if-then-else (join? (tail x))
(add (head x) (sumEveryOther (tail (tail x))))
(head x))))
这当然不是最佳的,因为它遍历列表两次,但它很短(“考试大小”)并完全在lanG中实现。
稍微长一点的解决方案,只使用累加器遍历列表一次:
(define (sumEvenOdd x evens odds odd?)
(if-then-else (const? x)
(if-then-else odd?
(join evens (add odds x))
(join (add evens x) odds))
(if-then-else odd?
(sumEvenOdd (tail x) evens (add (head x) odds) (negate odd?))
(sumEvenOdd (tail x) (add (head x) evens) odds (negate odd?)))))
(define (sumAtEvenAndOdd xs)
(sumEvenOdd xs 0 0 (bool #t)))
答案 1 :(得分:0)
所以join
就像一对join-e2
可能是join?
。要循环使用它,您可以使用带有点列表的pair?
进行循环,因为您的示例中的正确列表以const结尾。
(let loop ((lst '(1 2 3 4 5 6 . 7)) (o 0) (e 0) (odd? #t))
(let* ((ele (if (pair? lst) (car lst) lst))
(no (if odd? (+ ele o) o))
(ne (if odd? e (+ ele e))))
(if (pair? lst)
(loop (cdr lst) no ne (not odd?))
(cons no ne))))
答案 2 :(得分:0)
这是一个简单的递归解决方案。
(define (sum-even/odd xs)
(if (null? xs)
(values 0 0)
(call-with-values
(λ () (sum-even/odd (cdr xs)))
(λ (e o) (values (+ (car xs) o) e)))))
> (sum-even/odd '(1 2 3 4 5 6 7))
16
12