Оценка части Clojure cond

Пытаясь выполнить упражнение 1.16 (итеративная версия fast-exp) в разделе «Структура и интерпретация компьютерных программ» с помощью Clojure, я пришел к следующему выводу:

(defn fast-it-exp [base exp res]
  (cond (= exp 0) res
  (odd? exp) fast-it-exp base (- exp 1) (* base res)
  :else fast-it-exp base (/ exp 2) (* base base res)))

Пробуем:

user=> (fast-it-exp 0 0 10)
10   ;yep
user=> (fast-it-exp 2 2 2)
1     ;no...
user=> (fast-it-exp 1 1 1)
#<user$fast_it_exp__59 user$fast_it_exp__59@138c63>    ;huh?!

Кажется, что «нечетная» часть выражения cond возвращает функцию вместо оценки. Почему? Я пытался заключать выражения в скобки после предикатов, но это кажется неправильным синтаксисом, это лучшее, что я смог придумать. Я использую версию 1146 Clojure.


person Lars Westergren    schedule 18.01.2009    source источник
comment
Если вы хотите применить функцию, то она, вероятно, должна иметь открывающую скобку слева от себя. И в вашей последней строке нет ( перед fast-it-exp. И не только в последней строке…   -  person Display Name    schedule 05.03.2015


Ответы (2)


Попробуй это:

 (defn fast-it-exp [base exp res]
  (cond (= exp 0) res
        (odd? exp) (fast-it-exp base (- exp 1) (* base res))
        :else (fast-it-exp base (/ exp 2) (* base base res))))

У меня нет под рукой REPL, но похоже, что вы хотите.

person Phil Calçado    schedule 18.01.2009
comment
Какого черта, я думал, что перепробовал все возможные перестановки скобок, но, похоже, пропустил правильный. Это сработало, большое спасибо, Филипп. :) - person Lars Westergren; 18.01.2009
comment
Ахум. Почему перестановки скобок? Если вы хотите вызвать функцию в Лиспе, она должна быть первым элементом списка; так работает синтаксис Лиспа. - person Svante; 18.01.2009
comment
В Clojure круглые скобки после предиката необязательны, как и в приведенном выше примере (= exp 0). Пробовал без, но этот синтаксис был неоднозначным. Пробовал с , но, возможно, у меня были скобки вокруг :else, что было неправильно. Думал, что тоже попробовал версию Филиппа, но, должно быть, сделал что-то не так. - person Lars Westergren; 19.01.2009
comment
В lisp добавление или удаление скобок меняет смысл. В Clojure круглые скобки после предиката необязательны, как и после (= exp 0). Нет, круглых скобок нет, потому что нужно значение res. (res) будет означать вызов функции, которую также оценивает res, значение, сильно отличающееся от самого res. - person Shannon Severance; 05.03.2015

В принципе, то, что вы написали, можно было бы переформатировать как:

(defn fast-it-exp [base exp res]
  (cond
    (= exp 0) res
    (odd? exp) fast-it-exp
    base (- exp 1)
    (* base res) :else
    fast-it-exp base
    (/ exp 2) (* base base res)))

So:

user=> (fast-it-exp 0 0 10) ; (= exp 0) => res
10   ;yep
user=> (fast-it-exp 2 2 2)  ; base => (- exp 1)
1     ;no...
user=> (fast-it-exp 1 1 1)  ; (odd? exp) => fast-it-exp
#<user$fast_it_exp__59 user$fast_it_exp__59@138c63>    ;huh?!
person Chris Turner    schedule 20.01.2009
comment
А, понятно, это объясняет исходное поведение, спасибо. Кроме того, теперь мне удалось правильно посчитать, хех. румянец - person Lars Westergren; 21.01.2009