我发现我很少在Clojure中使用let
。出于某种原因,当我开始学习并从那时起就避免使用它时,我不喜欢它。感觉就像let
出现时流量停止了。我想知道,你认为我们可以完全没有它吗?
答案 0 :(得分:12)
让我们提供一些好处。首先,它允许在功能上下文中进行值绑定。其次,它赋予了可读性好处。因此,虽然从技术上讲,人们可以废除它(在某种意义上你可以在没有它的情况下编程),如果没有一个有价值的工具,语言就会变得贫穷。
关于let的一个好处是它有助于形式化指定计算的常用(数学)方法,其中引入方便的绑定,然后引入简化的公式。很明显,绑定只适用于那个“范围”,它与更多的数学公式相结合是有用的,特别是对于更多功能的程序员。
让阻塞出现在像Haskell这样的其他语言中并不是巧合。
答案 1 :(得分:12)
您可以(let [a1 b1 a2 b2...] ...)
替换任何((fn [a1 a2 ...] ...) b1 b2 ...)
,所以是的,我们可以。我虽然使用了很多,但我宁愿不做它。
答案 2 :(得分:6)
让我在防止宏中的多次执行方面是必不可少的:
(defmacro print-and-run [s-exp]
`(do (println "running " (quote ~s-exp) "produced " ~s-exp)
s-exp))
会运行两次s-exp,这不是我们想要的:
(defmacro print-and-run [s-exp]
`(let [result# s-exp]
(do (println "running " (quote ~s-exp) "produced " result#)
result#))
通过将表达式的结果绑定到名称并引用该结果两次来解决此问题。
因为宏返回的表达式将成为另一个表达式的一部分(宏是生成s表达式的函数),它们需要生成本地绑定以防止多次执行并避免符号捕获。 / p>
答案 3 :(得分:5)
我想我理解你的问题。如果错了,请纠正我。有时候“let”用于命令式编程风格。例如,
... (let [x (...)
y (...x...)
z (...x...y...)
....x...y...z...] ...
这种模式来自命令式语言:
... { x = ...;
y = ...x...;
...x...y...;} ...
你避免这种风格,这就是为什么你也避免“让”,不是吗?
在某些问题中,命令式样式会减少代码量。此外,有时用java或c写入更有效。 在某些情况下,“let”只保存子表达式的值,而不管评估顺序如何。例如,
(... (let [a (...)
b (...)...]
(...a...b...a...b...) ;; still fp style
答案 4 :(得分:2)
let
至少有两个重要的用例 - 绑定:
首先,正确使用let
可以使您的代码更清晰,更短。如果你有一个多次使用的表达式,那么在let
中绑定它是非常好的。以下是使用map
的标准函数let
的一部分:
...
(let [s1 (seq c1) s2 (seq c2)]
(when (and s1 s2)
(cons (f (first s1) (first s2))
(map f (rest s1) (rest s2)))))))
...
即使您只使用一次表达式,它仍然可以帮助(对于未来的代码读者)给它一个语义上有意义的名称。
其次,正如Arthur所提到的,如果你想多次使用一个表达式的值,但只希望它被评估一次,你不能简单地输出整个表达式两次:你需要某种绑定。如果你有一个纯粹的表达方式,那将只是浪费:
user=> (* (+ 3 2) (+ 3 2))
25
但如果表达式有副作用,实际上会改变程序的含义:
user=> (* (+ 3 (do (println "hi") 2))
(+ 3 (do (println "hi") 2)))
hi
hi
25
user=> (let [x (+ 3 (do (println "hi") 2))]
(* x x))
hi
25
答案 5 :(得分:0)
最近偶然发现了一些时间:
(testing "Repeat vs Let vs Fn"
(let [start (System/currentTimeMillis)]
(dotimes [x 1000000]
(* (+ 3 2) (+ 3 2)))
(prn (- (System/currentTimeMillis) start)))
(let [start (System/currentTimeMillis)
n (+ 3 2)]
(dotimes [x 1000000]
(* n n))
(prn (- (System/currentTimeMillis) start)))
(let [start (System/currentTimeMillis)]
(dotimes [x 1000000]
((fn [x] (* x x)) (+ 3 2)))
(prn (- (System/currentTimeMillis) start)))))
Output
Testing Repeat vs Let vs Fn
116
18
60
'让'赢得'纯'功能。