使Clojure let语句更具功能性

时间:2019-01-30 22:01:33

标签: clojure functional-programming purely-functional

在我的第一个Clojure项目中,除最后部分外,一切都很好:

(let [broken-signs    (->> (:symbols field)
                           (map make-sign)
                           (filter broken?))
      broken-count    (count broken-signs)
      unfixable-count (-> (filter (complement fixable?) broken-signs)
                          (count))]
  (println
    (if (> unfixable-count 0)
      -1
      (- broken-count unfixable-count))))

缩进看起来不起作用,因为我正在重用let块中的状态。我基本上是先计算破损标志的数量,然后再计算可固定标志的数量。如果有任何不可修复的标志,则打印-1,否则将打印要修复的标志的数量。

如果我两次映射/过滤,我将有重复的代码,但大多数情况下运行起来会更慢。仍然有一种方法可以改进此代码吗?

编辑:这就是我所决定的

 (defn count-broken-yet-fixable []
   (let [broken (->> (:symbols field)
                     (map make-sign)
                     (filter broken?))
         unfixable (remove fixable? broken)]
     (when (empty? unfixable)
       (count broken))))

 (defn solve-task []
   (if-let [result (count-broken-yet-fixable)]
     result
     -1))

(println (solve-task))

确实没有必要进行减法运算,也不必在let块中进行计数。在输入错误时输出-1也不是函数的工作,而只是任务的一部分。

3 个答案:

答案 0 :(得分:9)

我认为您的方法没有任何“功能失常”或错误。压痕看起来不错。

(let [broken (->> (:symbols field)
                  (map make-sign)
                  (filter broken?))
      unfixable (remove fixable? broken)]
  (when (seq unfixable)
    (- (count broken) (count unfixable))))
  • 您可以将filter (complement替换为remove
  • 可以使用pos?代替(> n 0)
  • 我可能会在println中放入两个if,但实际上最好返回一个值
  • 您可以内联broken-count绑定,因为它仅在一个地方使用
  • 我个人认为,使用更少的线程宏更容易阅读
  • 由于需要计算unfixable是有条件的,因此您可以先使用seq测试值
  • 如果您返回-1作为标记值,​​我会改用nil;如果不满足when条件,这种情况自然发生
  • 条件逻辑似乎倒退:-1为正时返回unfixable-count,仅当其为非正数时使用它的值(这意味着b / c计数为零不能为负),例如可以将其重写为(- broken-count 0),然后再重写为broken-count

答案 1 :(得分:1)

(let [broken-signs (->> (:symbols field)
                        (map make-sign)
                        (filter broken?))]
  (if-let [unfixable-signs (seq (remove fixable? broken-signs))]
    -1
    (- (count broken-signs) (count unfixable-signs)))

您的代码已经非常整洁并且布局合理。我唯一想做的更改就是尽可能长时间地停留在域中-在这种情况下,signs对象。并且仅在以后使用计数。

然后,返回值可以使用print进行实际操作。

答案 2 :(得分:0)

您的代码没有副作用(除了打印,我们将修复它),因此我不会说它不起作用。 let用于建立中间值。在评论中有一些潜在的改进。

                      ; align here (controversial)
(let [broken-signs    (->> (:symbols field)
                           (map make-sign)
                           (filter broken?))
      broken-count    (count broken-signs)
      unfixable-count (->> broken-signs ; maybe emphasize non-function start
                           (filter (complement fixable?))
                           count)] ; no parens needed
  ;; don't print; just return number
  (if (< 0 unfixable-count)  ; prefer less-than (Elements of Clojure book)
    -1
    (- broken-count unfixable-count)))

我强烈推荐Clojure Style Guide以获得相关建议。