功能性Clojure或命令式Groovy更具可读性吗?

fox*_*nut 15 groovy functional-programming clojure imperative-programming

好的,现在不要作弊.

不,真的,花一两分钟试试这个.

"职位"有什么作用?

编辑:根据cgrand的建议进行简化.

(defn redux [[current next] flag] [(if flag current next) (inc next)])

(defn positions [coll]
  (map first (reductions redux [1 2] (map = coll (rest coll)))))
Run Code Online (Sandbox Code Playgroud)

现在,这个版本怎么样?

def positions(coll) {
  def (current, next) = [1, 1]
  def previous = coll[0]
  coll.collect {
    current = (it == previous) ? current : next
    next++
    previous = it
    current
  }
}
Run Code Online (Sandbox Code Playgroud)

我正在学习Clojure,我很喜欢它,因为我一直很喜欢函数式编程.我花了更长的时间来提出Clojure解决方案,但我很高兴不得不考虑一个优雅的解决方案.Groovy解决方案没问题,但我发现这种命令式编程很无聊和机械化.经过12年的Java,我觉得Clojure的功能和编程是我需要的提升.

对,明白了.好吧,我必须诚实地说,我想知道我几个月后回到它时是否会理解Clojure代码.当然,我可以评论它,但我不需要评论我的Java代码来理解它.

所以我的问题是:这是一个越来越习惯函数式编程模式的问题吗?函数式编程大师是否正在阅读此代码并轻松理解它?觉得哪个版本更容易理解?

编辑:这段代码的作用是根据玩家的积分计算玩家的位置,同时跟踪那些被捆绑的玩家.例如:


Pos Points
1. 36
1. 36
1. 36
4. 34
5. 32
5. 32
5. 32
8. 30
Run Code Online (Sandbox Code Playgroud)

Bri*_*per 22

我认为没有固有的可读性.这是你习惯的,你不习惯的.我能够读取您的代码的两个版本.我实际上可以更轻松地阅读你的Groovy版本,即使我不知道Groovy,因为我也花了十年时间研究C和Java,而且只用了一年时间看Clojure.这并没有说明语言,它只是说了一些关于我的事情.

同样地,我比西班牙语更容易阅读英语,但这也没有说明这些语言的内在可读性.(在简单性和一致性方面,西班牙语实际上可能是两者中"更易读"的语言,但我仍然无法阅读它).我现在正在学习日语,并且经历了一段艰难时期,但是日本本土人士对英语也是如此.

如果你一生中大部分时间都在阅读Java,那么看起来像Java的东西比那些没有Java的东西更容易阅读.直到你花了很多时间看Lispy语言看着类似C语言,这可能仍然存在.

要了解某种语言,您必须熟悉以下内容:

  • 语法([vector]vs. (list),hyphens-in-names)
  • 词汇(什么reductions意思?你怎么样/在哪里查找它?)
  • 评估规则(将函数视为对象是否有效?在大多数语言中都是错误的.)
  • 习语,就像 (map first (some set of reductions with extra accumulated values))

所有这些都需要时间,练习和重复来学习和内化.但是如果你在接下来的6个月里阅读和撰写大量的Clojure,你不仅可以在6个月后理解Clojure代码,你可能会比现在更好地理解它,甚至可以简化它.这个怎么样:

(use 'clojure.contrib.seq-utils)                                        ;;'
(defn positions [coll]
  (mapcat #(repeat (count %) (inc (ffirst %)))
          (partition-by second (indexed coll))))
Run Code Online (Sandbox Code Playgroud)

看看我一年前写过的Clojure代码,我对它有多糟糕感到震惊,但我能读得很好.(不是说你的Clojure代码太可怕了;我根本没有阅读它,我不是大师.)


Tim*_*ley 8

编辑:可能不再相关.

Clojure对我来说很复杂.它包含更多需要理解的抽象.这是使用更高阶函数的代价,你必须知道它们的含义.因此,在一个孤立的案例中,必要性需要较少的知识.但抽象的力量在于它们的组合方式.必须读取和理解每个命令循环,而序列抽象允许您消除循环的复杂性并组合强大的操作.

我进一步争辩说Groovy版本至少部分功能,因为它使用了collect,它实际上是map,一个更高阶的函数.它也有一些状态.

以下是我将如何编写Clojure版本:

(defn positions2 [coll]
  (let [current (atom 1)
        if-same #(if (= %1 %2) @current (reset! current (inc %3)))]
    (map if-same (cons (first coll) coll) coll (range (count coll)))))
Run Code Online (Sandbox Code Playgroud)

这与Groovy版本非常相似,因为它使用了一个可变的"当前",但不同之处在于它没有next/prev变量 - 而是使用不可变序列.正如Brian所说,可读性不是内在的.这个版本是我对这个特殊情况的偏好,似乎坐在中间的某个地方.


cgr*_*and 8

我同意蒂莫西的观点:你引入了太多的抽象.我重写了你的代码并以:

(defn positions [coll]
  (reductions (fn [[_ prev-score :as prev] [_ score :as curr]] 
                (if (= prev-score score) prev curr))
    (map vector (iterate inc 1) coll)))
Run Code Online (Sandbox Code Playgroud)

关于你的代码,

(defn use-prev [[a b]] (= a b))
(defn pairs [coll] (partition 2 1 coll))
(map use-prev (pairs coll))
Run Code Online (Sandbox Code Playgroud)

可以简单地重构为:

(map = coll (rest coll))
Run Code Online (Sandbox Code Playgroud)