Как написать функцию SUM на схеме?

Как написать на схеме функцию, которая суммирует числа во встроенных списках?

i.e. ((1) (2 3) (4) (5 6))

Я написал это, чтобы суммировать обычный список:

(define (sum list)
  (if (null? list)
      0
      (+ (car list) (sum (cdr list)))))

но я не уверен, как сделать встроенный.


person Layla    schedule 20.09.2013    source источник


Ответы (3)


У вас есть 3 случая:

(define (my-sum lst)
  (cond
    ; 1. the list is empty, so finish of by adding 0
    ([empty? lst]        0)
    ; 2. the first element is a list, so recurse down on the sublist, then do the rest
    ([list? (car lst)]   (+ (my-sum (car lst)) (my-sum (cdr lst))))
    ; 3. add the first element to the sum, then do the rest
    (else                (+ (car lst)          (my-sum (cdr lst))))))

так что вы просто пропустили средний случай.

Это будет работать независимо от глубины вложенности:

(my-sum '((1) (2 3) (4) (5 6)))
=> 21

(my-sum '((1) (2 3) (4) (5 6 (7 8 (9)))))
=> 45

Обратите внимание, что не следует использовать имена «сумма» и «список», чтобы не затенять встроенные процедуры.

person uselpa    schedule 20.09.2013
comment
Нет ничего плохого в затенении встроенных функций, которые не используются в процедуре, поскольку это не приведет к утечке привязки за пределы определения. - person Sylwester; 20.09.2013
comment
@Sylwester Это сработает, но я считаю, что это плохая практика - рано или поздно это вас укусит. - person uselpa; 20.09.2013

Вот самый простой ответ.

(define (sum list-of-lists)
  (apply + (apply append list-of-lists)))

и "доказательство":

> (sum '((1) (2 3) (4) (5 6)))
21
person GoZoner    schedule 20.09.2013

Более функциональным способом

; this sums the elements of a not-embedded list
(define (sum-list* l)
  (foldl + 0 l))

; this sums the elements of an embedded list
(define (sum-embedded-list* el)
  (foldl + 0 (map sum-list* el)))

Он охватывает случай составленного таким образом списка: ((a1...an) (b1...bn)...), где ai и bj — атомы. Foldl и map — две важные функции в схеме (и других языках). Если вы не знаете, как их использовать, вы должны научиться. Посмотрите здесь

person Modestino    schedule 20.09.2013
comment
или просто (foldl + 0 (сумма-список карт* el)) - person uselpa; 20.09.2013
comment
но это работает только на один уровень ниже - попробуйте с '((1) (2 3) (4) (5 6 (7 8 (9)))) как в моем ответе - person uselpa; 20.09.2013
comment
Да, работает только на один уровень вниз. Ваш код охватывает случай вложенного списка. Я не знаю, хочет ли Лейла перейти на один или несколько уровней ниже (он написал встроенные списки и этот пример), но я только указывал на возможность использования некоторых важных функций списка, которые могут сделать код более кратким. Однако спасибо за ваше разъяснение. - person Modestino; 20.09.2013
comment
Да, если вы хотите использовать foldl, то лучше использовать правый foldl*, который будет выполнять рекурсию car-cdr, где car — это список. - person WorBlux; 20.09.2013