2015-05-09 5 views
1

Я не понимаю, какие преимущества или недостатки в использовании let, потому что можно избежать использования let на всех, как в коде ниже?Зачем использовать * let * в функциях?

(defn make-adder [x] 
    (let [y x] 
    (fn [z] (+ y z)))) 
(def add2 (make-adder 2)) 

;; or without let 
(defn add2 [z] (+ 2 z)) 

(add2 4) 
+0

Здесь есть две вещи - функция, которая генерирует функции, а также использует let. В последнем примере вырезаются оба. – pete23

ответ

7

В большинстве языков программирования, вы можете объявить и использовать локальные переменные, что помогает вы в дизайне тела функции (или метода). В Clojure, let позвоните свяжите локальные символы в любое выражение, которое может привести к значению, структуре данных или другому определению локальной функции.

Ваш пример настолько прост, что нет необходимости в конструкции let, но вы скоро столкнетесь с случаями, когда это будет очень полезно для читаемости логики функций.

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

И последнее, но не менее важное: letdestructuring очень удобно создавать сжатый код, когда выражения возвращают составные структуры, такие как коллекции.

7

Там три основные причины назвать промежуточные результаты:

  1. Вы хотите, чтобы помочь программистам (включая себя) понять, что они, по всей линии.
  2. Вы хотите кэшировать их, чтобы их можно было использовать в нескольких местах без необходимости повторного вычисления выражения. Это особенно важно, если оценка вашего выражения имеет побочные эффекты, и вы только хотите, чтобы они произошли один раз.
  3. Вы создаете closure, который будет использовать имя let, но не выдаст его внешнему миру.

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

Просто потому, что он у меня в руки, вот некоторый код из another recent answer of mine:

(defn trades-chan 
    "Open the URL as a tab-separated values stream of trades. 
    Returns a core.async channel of the trades, represented as maps. 
    Closes the HTTP stream on channel close!" 
    [dump-url] 
    (let[stream (-> dump-url 
       (client/get {:as :stream}) 
       :body) ;;This is an example of 3. 
     lines (-> stream 
       io/reader 
       line-seq) 
     ;; This is an example of 2. I don't want to make multiple readers just because I use them in multiple expressions. 

     ;;fields and transducer are examples of 1. 
     fields (map keyword (str/split (first lines) #"\t")) 
     transducer (map (comp #(zipmap fields %) #(str/split % #"\t"))) 

     ;;output-chan is another example of 2 
     output-chan (async/chan 50 transducer)] 
    (async/go-loop [my-lines (drop 1 lines)] 
        (if (async/>! output-chan (first my-lines)) 
        (recur (rest my-lines))   
        (.close stream))) ;;Here, the closure closes the HTTP stream, so it needs a name to refer to it by.    
    output-chan)) 
2

Вопрос заключается не в том, чтобы использовать let, но будет ли определить вашу add2 функцию непосредственно или использовать функцию решения-функции , make-adder, чтобы сделать это.

Ваша функция решений-функция

(defn make-adder [x] 
    (let [y x] 
    (fn [z] (+ y z)))) 

Как @user1571406 словам, let не делает ничего полезного здесь, и лучше опустить, давая

(defn make-adder [x] 
    (fn [z] (+ x z))) 

... что гораздо проще читать. Мы можем видеть, что, учитывая число, то оно возвращает функцию, которая добавляет, что число к тому, что оно представлено с:

((make-adder 2) 4) 
;6 

Давать (make-adder 2) имя просто сбивает с толку.

Определение его явно, безымянная функция, которая добавляет 2 является

(fn [z] (+ 2 z)) 

Применяя его к 4:

((fn [z] (+ 2 z)) 4) 
;6 
Смежные вопросы