2015-02-09 1 views
2

Привет, я немного новичок в программировании Clojure/Lisp, но я использовал рекурсию раньше на C-подобных языках, я написал следующий код, чтобы суммировать все числа, которые можно разделить на три от 1 до 100.Суммируя все кратные три рекурсивно в Clojure

(defn is_div_by_3[number] 
    (if(= 0 (mod number 3)) 
    true false) 
) 

(defn sum_of_mult3[step,sum] 
    (if (= step 100) 
    sum 
    ) 
    (if (is_div_by_3 step) 
    (sum_of_mult3 (+ step 1) (+ sum step)) 
    ) 
) 

Моя мысль была закончить рекурсию, когда шаг достигает суммы, то я бы все кратные мне нужно в переменную сумму, что я вернусь, но мой РЕПЛ, кажется, возвращая ноль для обоих переменные, что может быть неправильно здесь?

+0

Будучи учеником сам (и не только на вас), разве было бы более эффективно просто перебирать кратные три? например например '(reduce + (take-while # (<% 100) (итерация (частичная + 3) 0)))'. – cfrick

ответ

1

Есть несколько проблем с этим кодом.

1) Ваш первый if в sum_of_mult3 является noop. Ничто из этого не может повлиять на выполнение функции.

2) второй if в sum_of_mult3 имеет только одно условие, прямая рекурсия, если шаг кратен 3. Для большинства чисел первая ветвь не будет взята. Вторая ветвь просто неявная nil. Какая ваша функция будет гарантированно возвращаться независимо от ввода (даже если первый предоставленный аргумент является кратным трем, следующее повторное значение не будет).

3) если возможно использование recur вместо самозапуска, самозапуска потребляют стек, recur компилируется в простой цикл, который не потребляет стек.

Наконец, некоторые вопросы типа:

1) всегда ставил закрытия скобки на той же линии с блоком они закрываются. Это делает код стиля Lisp более удобочитаемым, и если больше ничего из нас не читает также код стиля Algol и не помещает парсеры в нужное место, мы напоминаем, какой язык мы читаем.

2) (if (= 0 (mod number 3)) true false) такое же, как (= 0 (mod number 3) который, в свою очередь, является идентичным (zero? (mod number 3))

3) использовать (inc x) вместо (+ x 1)

4) в течение более двух возможных действий, использовать case, cond или condp

(defn sum-of-mult3 
    [step sum] 
    (cond (= step 100) sum 
     (zero? (mod step 3)) (recur (inc step) (+ sum step)) 
     :else (recur (inc step) sum)) 
4

if является выражением не заявления. Результат if всегда является одной из ветвей. На самом деле у Clojure нет заявлений here:

Clojure-программы состоят из выражений. Компонент считает, что каждая форма, не обработанная специально специальной формой или макросом, является выражением, которое оценивается для получения значения. Нет никаких заявлений или утверждений, хотя иногда выражения могут оцениваться по их побочным эффектам, а их значения игнорируются.

Существует хороший онлайн (и бесплатно) книга для начинающих: http://www.braveclojure.com

Другое дело, круглые скобки в Лиспах не эквивалентны фигурные скобки в C-языках. Например, я хотел бы написать is_div_by_3 функции:

(defn div-by-3? [number] 
    (zero? (mod number 3))) 

Я хотел бы также использовать более идиоматический подход к sum_of_mult3 функции:

(defn sum-of-mult-3 [max] 
    (->> (range 1 (inc max)) 
     (filter div-by-3?) 
     (apply +))) 

Я думаю, что этот код гораздо более выразительными в своем намерении то рекурсивная версия. Единственным трюком является последний макрос ->>. Посмотрите на this answer для объяснения темы последнего макроса.

+0

Педантичное наблюдение: вам не нужен ваш диапазон, чтобы начать с 1, а не по умолчанию 0. –

+0

@DiegoBasch Я знаю это, я сделал это, потому что думал, что будет более ясно. –

0

В дополнение к ответу Родриго, вот первый способ, который я решил решить e:

(defn sum-of-mult3 [n] 
    (->> n 
     range 
     (take-nth 3) 
     (apply +))) 

Это должно быть понятно. Вот более «математический» способ без использования последовательности, принимая во внимание, что сумма всех чисел до N включительно составляет (N * (N + 1))/2.

(defn sum-of-mult3* [n] 
    (let [x (quot (dec n) 3)] 
    (* 3 x (inc x) 1/2))) 

Как Родриго сказал, рекурсия не правильный инструмент для этой задачи.