2012-02-05 3 views
3

Прежде всего, это домашнее задание, но я просто ищу намек или псевдокод о том, как это сделать.Общая сумма баллов

Мне нужно суммировать все элементы в списке, используя рекурсия. Однако ему нужно вернуть пустой набор, если он встречает что-то в списке, который не является числом. Вот моя попытка:

(DEFINE sum-list 
    (LAMBDA (lst) 
    (IF (OR (NULL? lst) (NOT (NUMBER? (CAR lst)))) 
     '() 
     (+ 
     (CAR lst) 
     (sum-list (CDR lst)) 
    ) 
    ) 
) 
) 

Это не удается, потому что он не может добавить пустой набор к чему-то другому. Обычно я просто возвращаю 0, если это не число и продолжаю обрабатывать список.

ответ

3

я бы пойти на это:

(define (mysum lst) 
    (let loop ((lst lst) (accum 0)) 
    (cond 
     ((empty? lst) accum) 
     ((not (number? (car lst))) '()) 
     (else (loop (cdr lst) (+ accum (car lst))))))) 
+0

Мне потребовалось много времени, чтобы выяснить, как это работает, особенно с двойным lst на второй линии. Я мог только представить версию с двумя параметрами. – rem45acp

+0

Вы можете заменить (lst lst) на (lst2 let) и изменить каждое вхождение lst ниже, что с lst2; это может сделать его более ясным. В основном он создает локальную переменную let (или lst2), которая инициализируется значением исходного параметра lst. – uselpa

0

Попробуйте сделать функцию «is-any-nonnumeric» (используя рекурсию); то вы просто (или (is-any-numeric list) (список сумм)) tomfoolery.

4

Предлагаю вам использовать и вернуть накопитель для хранения суммы; если вы найдете нечетное число при прохождении списка, вы можете сразу же вернуть пустой список , иначе рекурсия продолжается до тех пор, пока список не будет исчерпан.

Что-то вдоль этих линий (! Заполнить пробела):

(define sum-list 
    (lambda (lst acc) 
    (cond ((null? lst) ???) 
      ((not (number? (car lst))) ???) 
      (else (sum-list (cdr lst) ???))))) 

(sum-list '(1 2 3 4 5) 0) 
> 15 

(sum-list '(1 2 x 4 5) 0) 
>() 
+0

Мне нравится идея двух параметров, но это может действительно быть сделано только с одним параметром? – rem45acp

+2

это может быть, но лучший способ, который на самом деле будет работать, который я могу придумать, требует 2 'if' -операций и' let'. Лучше всего использовать двухпараметрическую версию (возможно, с помощью функции-обертки, которая просто вызывает '(внутренняя функция x 0)'). Кроме того, если вы еще успели запустить хвостовую рекурсию, две версии параметров являются хвостовыми рекурсивными, а никакой версии с одним параметром не будет. – Retief

2

Вашего вопросом является то, что вам нужно использовать конд, а не если - есть три возможных ветвь, которые необходимо учитывать. Во-первых, если вы запустили число, отличное от числа, второе - это когда вы запустите в конец списка, а третий - когда вам нужно перечислить следующий элемент списка. Первая проблема заключается в том, что вы комбинируете случай без номера и случай с пустым списком, который должен возвращать разные значения. Рекурсивный случай в основном правильный, но вам нужно будет проверить возвращаемое значение, поскольку рекурсивный вызов может возвращать пустой список.

+0

Если я отделяю случай не номера и пустой случай списка, я думал вернуть 0 для пустого списка и '() для не числа. Но опять же, когда рекурсия называется ее попыткой добавить пустой список к тому, что он накапливал раньше, создавая исключение vm, подобное этому: (+ 3 '()). Я предполагаю, что единственный способ сделать это - это два параметра. – rem45acp

+0

@ rem45acp - хороший улов - вам нужно будет проверить возвращаемое значение перед добавлением текущего значения. Вероятно, вы могли бы объединить случай «в настоящее время в не номер» и случай «не номер, возвращенный из рекурсивного вызова», если вы не пропустите обработку остальной части списка без необходимости. – Retief

1

Потому что я не достаточно умен, чтобы понять, как это сделать в одной функции, давайте быть болезненно явное:

#lang racket 

; This checks the entire list for numericness 
(define is-numeric-list? 
    (lambda (lst) 
    (cond 
     ((null? lst) true) 
     ((not (number? (car lst))) false) 
     (else (is-numeric-list? (cdr lst)))))) 

; This naively sums the list, and will fail if there are problems 
(define sum-list-naive 
    (lambda (lst) 
    (cond 
     ((null? lst) 0) 
     (else (+ (car lst) (sum-list-naive (cdr lst))))))) 

; This is a smarter sum-list that first checks numericness, and then 
; calls the naive version. Note that this is inefficient, because the 
; entire list is traversed twice: once for the check, and a second time 
; for the sum. Oscar's accumulator version is better! 
(define sum-list 
    (lambda (lst) 
    (cond 
     ((is-numeric-list? lst) (sum-list-naive lst)) 
     (else '())))) 

(is-numeric-list? '(1 2 3 4 5)) 
(is-numeric-list? '(1 2 x 4 5)) 

(sum-list '(1 2 3 4 5)) 
(sum-list '(1 2 x 4 5)) 

Выход:

Welcome to DrRacket, version 5.2 [3m]. 
Language: racket; memory limit: 128 MB. 
#t 
#f 
15 
'() 
> 

Я подозреваю, что ваше домашнее задание ждет что-то подробнее академический.

Смежные вопросы