好吧,现在不作弊了。

不,真的,花一两分钟尝试一下。

“职位”有什么作用?

编辑:根据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)))))

现在,这个版本怎么样?

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

我正在学习 Clojure 并且我很喜欢它,因为我一直很喜欢函数式编程。我花了更长的时间才想出 Clojure 解决方案,但我很享受这样做 思考 一个优雅的解决方案。Groovy 解决方案还不错,但我现在发现了这种类型的命令式编程 无聊的 和机械。使用 Java 12 年之后,我觉得已经一成不变,而使用 Clojure 进行函数式编程正是我所需要的提升。

对了,进入正题。好吧,我必须诚实地说,我想知道几个月后我再回顾 Clojure 代码时是否能理解它。当然,我可以对其进行注释,但我不需要注释我的 Java 代码来理解它。

所以我的问题是:这是一个更习惯函数式编程模式的问题吗?函数式编程专家在阅读这段代码时是否觉得它很容易理解?哪个版本做了 找到更容易理解的吗?

编辑:这段代码的作用是根据玩家的分数计算他们的位置,同时跟踪那些平局的人。例如:


Pos Points
1. 36
1. 36
1. 36
4. 34
5. 32
5. 32
5. 32
8. 30
有帮助吗?

解决方案

我认为不存在内在可读性这样的东西。有你习惯的,也有你不习惯的。我能够正常阅读您的两个版本的代码。实际上,我可以更轻松地阅读您的 Groovy 版本,即使我不了解 Groovy,因为我也花了十年时间研究 C 和 Java,而只花了一年时间研究 Clojure。这并没有说明任何关于语言的事情,它只说明了一些关于我的事情。

同样,我可以比西班牙语更轻松地阅读英语,但这也没有说明这些语言的内在可读性。(就简单性和一致性而言,西班牙语实际上可能是这两种语言中“更具可读性”的语言,但我仍然看不懂)。我现在正在学习日语,并且经历了一段艰难的时期,但是以日语为母语的人对英语也有同样的看法。

如果您一生中的大部分时间都在阅读 Java,那么看起来像 Java 的东西当然会比不是 Java 的东西更容易阅读。除非您花同样多的时间研究 Lispy 语言和类 C 语言,否则这可能仍然是正确的。

要理解一门语言,您必须熟悉以下内容:

  • 句法 ([vector](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))))

看着我一年前写的 Clojure 代码,我对它的糟糕程度感到震惊,但我可以正常阅读。(并不是说你的 Clojure 代码很糟糕;我读起来没有任何困难,而且我不是大师。)

其他提示

我同意提摩太前书:大家介绍太多的抽象。我返工你的代码,并结束了:

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

关于你的代码,

(defn use-prev [[a b]] (= a b))
(defn pairs [coll] (partition 2 1 coll))
(map use-prev (pairs coll))

可以简单地重构为:

(map = coll (rest coll))

编辑:可能不相关了

在Clojure的一个是令人费解的我。它包含了更多的抽象这就需要理解。这是使用高阶函数的价格,你要知道他们的意思。因此,在一个孤立的事件,当务之急需要较少的知识。但是,抽象的能力,是在结合的手段。每个势在必行回路必须阅读和理解,而序列抽象允许你删除一个循环的复杂性,并结合强大的opperations。

我将进一步认为Groovy的版本至少部分功能的,因为它使用收集,这是真的映射,高阶函数。它有一些状态下,它也

下面是我会怎样写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)))))

这是非常相似的,因为它使用了可变的“当前” Groovy的版本,但不同之处在于它不具有下一个/上可变 - 而不是使用那些不可变的序列。布赖恩elloquently所说,可读性不征。这个版本是我对这种特殊情况下的偏好,并似乎在中间的某个地方坐。

乍一看,Clojure 更为复杂。虽然它可能更优雅。面向对象是使语言在更高层次上更加“相关”的结果。函数式语言似乎有一种更“算法”(原始/基本)的感觉。这正是我此刻的感受。当我有更多使用 clojure 的经验时,也许情况会改变。

恐怕我们正在陷入哪种语言可以最简洁或者用最少的代码行解决问题的游戏。

这个问题对我来说有两个方面:

  1. 乍一看是否容易了解代码的用途?这对于代码维护者来说很重要。

  2. 猜测代码背后的逻辑有多容易?太冗长/啰嗦?太简洁了?

“让一切尽可能简单,但又不简单。”

艾尔伯特爱因斯坦

我也正在学习的Clojure和热爱它。但在这个阶段,我的发展,Groovy的版本是比较容易理解。我喜欢的Clojure虽然是阅读的代码,并具有“啊哈!”的经验,当你终于“搞定”到底是怎么回事。我的真正的享受是类似的经历,当你意识到所有的代码可以应用到其他类型的数据,在不改变代码的方式出现这种情况,几分钟后。我已经失去的时候我已经通过Clojure中的一些数字代码工作的数量计数,然后,过了一会儿,怎么同样的代码可能与使用的思想字符串,符号,窗口小部件,...

我使用的类比是关于学习的色彩。记住,当你介绍了红色?你了解它很快 - 有世界上所有的这件红色的东西。然后,你听说过这个词品红和失去了一会儿。但同样,多一点曝光后,你理解的概念,有一个更具体的方式来描述一个特定的颜色。你必须内化的概念,在你的脑袋持有更多的信息,但你最终的东西更强大,更简洁。

Groovy支持各种样式太解决这一问题的:

coll.groupBy{it}.inject([]){ c, n -> c + [c.size() + 1] * n.value.size() }

绝非重构是漂亮,但不是太难理解了。

我知道这是不是一个问题的答案,但我将能够“理解”的代码好得多,如果有测试,如:

assert positions([1]) == [1]
assert positions([2, 1]) == [1, 2]
assert positions([2, 2, 1]) == [1, 1, 3]
assert positions([3, 2, 1]) == [1, 2, 3]
assert positions([2, 2, 2, 1]) == [1, 1, 1, 4]

这会告诉我,一年从现在开始,什么代码是意料中的事。许多比我在这里看到的代码的任何优秀的版本更好。

我是确实的题外话?

另一件事是,我认为,“可读性”取决于上下文。这取决于谁将会维护代码。例如,为了维持Groovy代码(但是辉煌)的“功能性”的版本,它会不仅Groovy的程序员,但功能Groovy的程序员... 另外,更相关,例如是:如果几行代码,使其更容易理解为“初学者”的Clojure程序员,那么代码将整体更具可读性,因为它会通过一个较大的社区可以理解的:没有必要有研究Clojure的三年才能够把握的代码,并进行编辑了。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top