Clojure可以不用吗?

时间:2012-11-28 23:47:42

标签: clojure

我发现我很少在Clojure中使用let。出于某种原因,当我开始学习并从那时起就避免使用它时,我不喜欢它。感觉就像let出现时流量停止了。我想知道,你认为我们可以完全没有它吗?

6 个答案:

答案 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

'让'赢得'纯'功能。