使用球拍结构在偶数和奇数位置对元素求和

时间:2014-08-24 06:26:18

标签: scheme racket

在课堂上,我们使用以下球拍结构为编造语言(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行。

我事先感谢你的帮助。

3 个答案:

答案 0 :(得分:1)

我假设还有谓词来标识constjoin - 我们称之为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