我正在读这本书的第一版,虽然我很喜欢它,但给出的一些例子似乎已经过时了。我会放弃并找到另一本书来学习,但我对作者所说的内容真的很感兴趣,并且想让这些例子适合我自己,所以我正在尝试更新它们。
以下代码是分析依赖于 clojure.contrib 的文本的 map/reduce 方法。我尝试将 .split 函数更改为使用 #"\w+" 重新排序,使用 line-seq 而不是 read-lines,并将 .toLowerCase 更改为字符串/小写。我尝试将我的问题跟踪到源代码并彻底阅读文档以了解 read-lines 函数在您使用整个序列后关闭,并且 line-seq 返回一个惰性字符串序列,实现 java.io.BufferedReader。对我的问题最有帮助的是关于如何在 clojure 1.3 之后读取文件的帖子。即使这样,我也无法让它工作。
所以这是我的问题:我需要在以下代码中更改哪些依赖项和/或函数以使其成为现代、可靠、惯用的 Clojure?
第一个命名空间:
(ns chapter-data.word-count-1
(:use clojure.contrib.io
clojure.contrib.seq-utils))
(defn parse-line [line]
(let [tokens (.split (.toLowerCase line) " ")]
(map #(vector % 1) tokens)))
(defn combine [mapped]
(->> (apply concat mapped)
(group-by first)
(map (fn [[k v]]
{k (map second v)}))
(apply merge-with conj)))
(defn map-reduce [mapper reducer args-seq]
(->> (map mapper args-seq)
(combine)
(reducer)))
(defn sum [[k v]]
{k (apply + v)})
(defn reduce-parsed-lines [collected-values]
(apply merge (map sum collected-values)))
(defn word-frequency [filename]
(map-reduce parse-line reduce-parsed-lines (read-lines filename)))
第二个命名空间:
(ns chapter-data.average-line-length
(:use rabbit-x.data-anal
clojure.contrib.io))
(def IGNORE "_")
(defn parse-line [line]
(let [tokens (.split (.toLowerCase line) " ")]
[[IGNORE (count tokens)]]))
(defn average [numbers]
(/ (apply + numbers)
(count numbers)))
(defn reducer [combined]
(average (val (first combined))))
(defn average-line-length [filename]
(map-reduce parse-line reducer (read-lines filename)))
但是当我在 light table 中编译和运行它时,我得到了一堆错误:
1)在 word-count-1 命名空间中,当我在编辑后尝试重新加载 ns 函数时得到这个:
java.lang.IllegalStateException: spit already refers to: #'clojure.contrib.io/spit in namespace: chapter-data.word-count-1
2)在平均行长度命名空间中,在相同情况下,我会遇到类似的名称冲突错误:
clojure.lang.Compiler$CompilerException: java.lang.IllegalStateException: parse-line already refers to: #'chapter-data.word-count-1/parse-line in namespace: chapter-data.average-line-length, compiling:(/Users/.../average-line-length.clj:7:1)
3)奇怪的是,当我退出并重新启动 light table 时,将代码直接复制并粘贴到文件中(替换那里的内容)并调用其顶级函数的实例 word-count-1 命名空间运行良好,给了我出现的次数test.txt 文件中的某些单词,但平均行长命名空间给了我这个:
"Warning: *default-encoding* not declared dynamic and thus is not dynamically rebindable, but its name suggests otherwise. Please either indicate ^:dynamic *default-encoding* or change the name. (clojure/contrib/io.clj:73)...
4)此时,当我调用word-frequency
第一个命名空间的函数时,它返回nil
而不是单词出现的次数,当我调用average-line-length
第二个命名空间的函数时,它返回
java.lang.NullPointerException: null
core.clj:1502 clojure.core/val