我不明白使用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 :(得分:7)
命名中间结果的主要原因有三个:
let
- ed名称,但不会将其发送给外界。 在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))
答案 1 :(得分:7)
在大多数编程语言中,您可以声明并使用局部变量来帮助您设计函数(或方法)主体。在Clojure中,let
允许您将绑定本地符号绑定到任何可能导致值,数据结构或其他本地函数定义的表达式。
您的示例非常简单,不需要let
构造,但您很快就会遇到对函数逻辑可读性有很大帮助的情况。
let
也是一种分解代码的方法,它通过只计算一次表达式并在几个地方使用结果来提高可读性和性能。
最后但并非最不重要的是,当表达式返回像集合这样的复合结构时,let
destructuring非常便于生成简洁的代码。
答案 2 :(得分:2)
问题不在于是否使用let
,而是直接定义add2
函数还是使用函数制作函数make-adder
来制作它。
你的功能制作功能
(defn make-adder [x]
(let [y x]
(fn [z] (+ y z))))
正如Rust's regex engine所说,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