3

作为 clojure 的新手,我很难为不同的代码结构找到一种惯用的风格。

在某些情况下,我的 let 绑定包含函数的大部分代码。这是膨胀,对clojure哲学或惯用语的一些误解吗?

这是一个示例测试用例来演示。它测试到某个存储库的添加/获取往返。长让看起来很奇怪吗?

(deftest garden-repo-add-get
  (testing "Test garden repo add/get"
    (let [repo (garden/get-garden-repo)
          initial-garden-count (count (.list-gardens repo))
          new-garden (garden/create-garden "Keukenhof")
          new-garden-id (.add-garden repo new-garden)
          fetched-garden (.get-garden repo new-garden-id)]
      (is (= (+ initial-garden-count 1) (count (.list-gardens repo))))
      (is (= (.name new-garden) (.name fetched-garden))))))
4

3 回答 3

3

我在您的代码中看到的主要问题let是,通常情况下,您正在使用许多中间变量,这些变量只有名称才能存在于let form.

避免过度膨胀的最佳方法是使用箭头宏->->>

例如,您可以避免repo使用中间变量

initial-garden-count (-> (garden/get-garden-repo)
                         (.list-gardens)
                         count)

尽管如此,在您的特定情况下,您在测试验证中使用了所有中间变量,因此无论如何您都需要在 let 语句中使用它们。也许new-garden-id是您可以避免的唯一中间体:

fetched-garden (->> (.add-garden repo new-garden)
                    (.get-garden repo))

或者使用 Chiron 建议的方法:

fechted-gaden (.get-garden repo (.add-garden repo new-garden))
于 2013-10-21T12:58:03.477 回答
2

就个人而言,这就是我在 Clojure 中编码的方式。Clojure 足够简洁、优雅和简洁。
我认为通过压缩到以下内容不会是“惯用的”。

  (is (= (+ (count (.list-gardens repo)) 1) (count (.list-gardens (garden/get-garden-repo)))))

您的代码片段更易于理解、测试和调试(在 Eclipse、IntelliJ 中)。

Clojure 是关于简单的,我想保持这种方式。

不过,您的问题的答案是高度自以为是的。

于 2013-10-21T11:32:45.437 回答
0

通过查看您的函数代码,该函数正在使用的“事物”似乎是具有 getter/setter 和方法的典型 OO 对象(请参阅有很多 .{something} 调用),这使您使用这些 let 绑定是因为对象 API 的设计方式。如果您必须使用对象,那很好。

在 Clojure 中,您基本上围绕数据结构(如 map/vector/list/set 和函数)设计 API,这(在大多数情况下)为您提供了一种可能不需要太多 let 绑定使用的 API。

于 2013-10-21T12:09:46.343 回答