这是符合惯用的Clojure语言风格吗?

7

我开始使用Clojure做Project Euler作为学习Clojure的首次尝试。我已经解决了第一个任务:

找出1000以下3或5的倍数之和。

我以前用Python解决过这个问题:

sum(i for i in xrange(1000) if i%3==0 or i%5==0)

这是我第一次尝试编写Clojure代码:

(reduce +
  (filter 
    (fn [x]
      (or 
        (= 0 (mod x 3)) 
        (= 0 (mod x 5))))
    (range 1000)))

我对它的冗长感到惊讶,但我相信这是因为我的风格和对Clojure习语的无知。

那么,这段Clojure代码的习惯用法版本会是什么样子呢?

3个回答

9
这是我做的方式:
(apply +
  (filter #(or (zero? (mod % 3))
               (zero? (mod % 5)))
    (range 1000)))

我的解决方案稍微更符合惯用语,它使用了匿名函数读取宏“#(...)”和“zero?” “fn”。
你的解决方案是不同的,但同样好!
顺便说一句——解决欧拉问题是学习新语言的好方法——你不能从书本中获得一切。
编辑:
我决定提供一个与您的Python版本更相符的不同解决方案(在我看来不太美观)。
(apply +
  (for [i (range 1000) :when (or (zero? (mod i 3))
                                 (zero? (mod i 5)))]
    i))

非常感谢,这样清理得很干净!在这里使用apply和reduce有什么优势呢? - gumuz
1
“+”具有可变性,因此它防止我们多次执行“+”。实际上,这相当于使用“reduce”,因为一旦参数列表超过2个,“+”就会使用“reduce”(请参见“+”的源代码)。在这个例子中,这只是我的风格而已,没有其他什么。 - Kyle
谢谢你,还有一些风格指南,例如,倡导你对or参数进行对齐的方式吗? - gumuz
1
不幸的是,我仍在学习“正确”的风格 - 这是一篇很好的文章 - https://github.com/bbatsov/clojure-style-guide - 你会注意到我并没有完全遵循它 - Kyle
1
@gumuz 我添加了一个更符合您的Python解决方案的版本 - 在我的看法中不够简洁。 - Kyle
1
主题的变化:(apply + (for [i (range 1000) :when (some zero? (map (partial mod i) [3 5]))] i)) - A. Webb

9

另一种版本:

(defn sum-of [n]
  (reduce + (range n 1000 n)))

(+ (sum-of 3) (sum-of 5) (- (sum-of 15)))

2
可爱。另外,(reduce + (distinct (concat (range 3 1000 3) (range 5 1000 5)))) - ToBeReplaced

0

我喜欢尝试为事物寻找通用解决方案,例如Project Euler,以下是我的通用解决方案:

(defn sum-multiples [nums lim]
  (reduce
   +
   (filter
    (fn [x]
      (some identity
            (map #(zero? (mod x %)) nums)))
    (range lim))))

然后只需调用:

(sum-multiples [3 5] 1000)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接