定义Scheme函数

时间:2012-11-09 22:27:49

标签: scheme

所以我一直试图学习这种我从矿井的朋友那里听到的Scheme语言。他说我应该做的就是从小做起,然后努力去理解它。因此,在阅读了他曾经简要讨论过Scheme编程的教科书之后,我对自己的工作方式感到有些困惑。

所以我想要问的是,如果我想为一个被调用的函数添加一个定义,让我们从我已定义的几个列表中说'evens':

(DEFINE list0 (LIST 'j 'k 'l 'm 'n 'o 'j) )
(DEFINE list1 (LIST 'a 'b 'c 'd 'e 'f 'g) )
(DEFINE list2 (LIST 's 't 'u 'v 'w 'x 'y 'z) )
(DEFINE list3 (LIST 'j 'k 'l 'm 'l 'k 'j) )
(DEFINE list4 (LIST 'n 'o 'p 'q 'q 'p 'o 'n) )
(DEFINE list5 '((a b) c (d e d) c (a b) )
(DEFINE list6 '((h i) (j k) l (m n)) )
(DEFINE list7 (f (a b) c (d e d) (b a) f) )

这样就完成了以下任务:evens

我已经创建了一个加法器函数,我相信它是:

(DEFINE (adder lis)
    (COND
        ((NULL? lis) 0)
        (ELSE (+ (CAR lis) (adder (CDR lis))))
))

如果我希望它像下面的任务那样做,那么甚至可能是什么定义:

找齐: (evens 1st)应该返回一个新列表,由第1个偶数编号元素组成。

(evens '(a b c d e f g))
which would/should return:
(b d f)

(evens (LIST 's 't 'u 'v 'w 'x 'y 'z))
which would/should return:
(t v x z)

(evens '(f (a b) c (d e d) (b a) f) )
which would return:
((a b) (d e d) f)

和(evens'())和(evens'(a))

会返回空列表。

我一直在错误地练习,但我完全迷失了。提前致谢

好吧,我认为我已经为我的例子提出了一个递归函数,我一直试图解决这个问题:

 (define mylist '(1 2 3 4 5 6 7))
 (define (evens lst)
 (define (do-evens lst odd)
     (if (null? lst)
 lst
     (if odd
         (do-evens (cdr lst) #f)
         (cons (car lst) (do-evens (cdr lst) #t)))))
         (do-evens lst #t))

有什么想法吗?

3 个答案:

答案 0 :(得分:2)

首先,adder功能与您的问题无关,对吧?

考虑evens功能。您已经说(evens '())(evens '(a))应该返回空列表。 (evens '(a b))应该返回什么?那么(evens '(a b ...))呢?你看到如何设置递归吗?

答案 1 :(得分:2)

好的,所以要做一个遍历列表的递归函数,选择一些元素返回而不是其他元素,基本模式将是

(define (recur l)
  (cond
    ((null l) '())
    ((??????) (cons (car l) (recur (cdr l))))
    (else (recur (cdr l)))))

这是做什么的

  1. 列表是否为空?返回null。
  2. 如果列表不为null,我们是否应该保留列表中的第一项?好吧,让我们保留它并将其添加到(recur (cdr l))返回
  3. 否则,只需返回recur (cdr l)返回的内容。
  4. 我希望这清楚的是,一个简单的递归列表函数只查看列表的第一个元素,确定如何处理它,然后再次使用列表的其余部分调用自身。从某种意义上说,递归是一种简化计算的方法,只需处理数据的第一部分,并留下另一个函数来担心其余的数据(其他函数实际上是同一个函数你第一次打电话,但尽量不要担心)。例如,只返回偶数项的递归函数可能如下所示:

    (define (even-numbers l)
      (cond
        ((null? l) '())
        ((even? (car l)) (cons (car l) (even-numbers (cdr l))))
        (else (even-numbers (cdr l)))))
    

    那就是说,你的情况稍微复杂一点;你需要删除第一个元素,然后在每次连续调用函数时,执行与上一次调用相反的操作。

    这样做的一种方法是传递一个布尔状态,每次都会翻转它。请注意,由于 evens 函数不采用状态,因此您必须定义不同的内部函数并重复该函数:

    (define (evens l)
      (let loop ((lst l) (keep #f))
          (cond
             ((null? lst) '())
             ((eq? keep #t) (???????)
             (else (loop (cdr l) #t)))))
    

    考虑到前面的例子,你应该能够自己解决(???????)中的内容。我想,我为你做了一点太多的工作。

    另一种方法是使用相互递归的函数 evens odds 。考虑一下

    1. evens 是一个抛弃第一个元素然后在列表中工作的函数,每次执行相反(保留或丢弃)上次执行的操作。
    2. 赔率是一个保留第一个元素然后在列表中工作的函数,每次执行相反(保留或丢弃)上次执行的操作。
    3. 这意味着您可以定义

      1. evens 作为忽略第一个元素的函数,只需在列表的其余部分调用赔率
      2. 赔率作为保留第一个元素的函数,在列表的其余部分调用 evens 缺点 - 将第一个元素置于其上结果的开始。
      3. 这看起来像

        (define (evens l)
          (cond
            ((null? l) '())
            (else (odds (??????)))))
        
        (define (odds l)
          (cond
            ((null? l) '())
            (else (cons (car l) (evens (??????))))))
        

        希望这是有道理的。

        如果你真的想了解Scheme中的递归,请购买一份“The Little Schemer”并开始研究它。

答案 2 :(得分:0)

这个怎么样:

(define (evens l)
  (cond
   ((null? l) '())
   ((null? (cdr l)) '())
   (else (cons (cadr l) (evens (cddr l))))))

但我喜欢平均值和赔率答案!