Scheme 使用racket结构对奇偶位置的元素求和

Scheme 使用racket结构对奇偶位置的元素求和,scheme,racket,Scheme,Racket,在课堂上,我们使用以下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 lis

在课堂上,我们使用以下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)) 

此语言的宏定义为racket函数。一个简单的例子是:

(define (threeTimes x)
   (add x (add x x)))
(join (const 2) (const 8))

并且使用它看起来像:

(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
其结果将是:

(define (threeTimes x)
   (add x (add x x)))
(join (const 2) (const 8))
我试图通过将列表转换为球拍列表,用元素对位置进行ziping,从列表中过滤奇数或偶数元素来解决这个问题, 并使用这些列表的总和生成一对。这是可行的,但我太复杂了。教授说这个解决方案大约有5行长


我提前感谢您的帮助。

因此,
加入
就像一对情侣,
join-e2
可以是
加入?
。要循环使用它,您可以使用点列表执行与使用
pair?
相同的操作,因为在您的示例中,正确的列表以常量结束

(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))))

下面是一个简单的递归解决方案

(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

我假设还有谓词来标识
常量
连接
——让我们称它们为
常量
连接

假设我们有一个函数,可以将列表中的每一项相加,
sumAtEvenAndOdd
可以如下所示:

(define (sumAtEvenAndOdd xs)
  (join (sumEveryOther (tail xs)) (sumEveryOther xs)))
(define (sumEveryOther x)
  (if-then-else (const? x)
                x
                (if-then-else (join? (tail x))
                              (add (head x) (sumEveryOther (tail (tail x))))
                              (head x))))
然后,
sumEveryOther
可以这样实现:

(define (sumAtEvenAndOdd xs)
  (join (sumEveryOther (tail xs)) (sumEveryOther xs)))
(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)))

是的,它是一个过程/解释器,解析用上述结构编写的程序。对不起,我不想发布消息来源,这样我就不会有麻烦了。我感兴趣的主要事情是,我如何循环搜索一个列表。通常一个列表会以null或其他东西结尾,这样人们就知道什么时候停止对它的递归。