clojure 初学者:标记不同字符的列表

Beginner in clojure: Tokenizing lists of different characters

所以我知道这不是解决此问题的最佳方法,但我正在尝试遍历输入文件中的行列表,这些行最终成为表达式。我有一个表达式列表,由于拆分列表功能,每个表达式都有自己的列表。我的下一步是用 id 替换字符,用 int 替换整数,用 addop 替换 + 或 -。我有正则表达式来查找我的符号是否匹配其中任何一个,但是当我尝试替换它们时,我只能得到我调用的最后一个 for 循环以留下任何持久的结果。我知道它归结为函数式编程的工作方式,但我无法全神贯注于该程序的踪迹,以及如何替换每种单独类型的输入并将结果全部保存在一个列表中。

(def reint #"\d++")
(def reid #"[a-zA-Z]+")
(def readdop #"\+|\-")

(def lines (into () (into () (clojure.string/split-lines (slurp "input.txt")) )))

(defn split-the-line [line] (clojure.string/split line #" " ))

(defn split-the-list  [] (for [x (into [] lines)] (split-the-line x)))

(defn tokenize-the-line [line] 
(for [x line] (clojure.string/replace x reid "id")) 
(for [x line] (clojure.string/replace x reint "int")) 
(for [x line] (clojure.string/replace x readdop "addop")))

(defn tokenize-the-list [] (for [x (into [] (split-the-list) )] (tokenize-the-line x)))

你可能会说,我是函数式编程的新手,所以欢迎任何建议!

您正在使用 do 块,它计算多个表达式(通常用于副作用)然后 return 是最后一个。您看不到它,因为 fn(因此 defn)隐式包含一个。因此,行

(for [x line] (clojure.string/replace x reid "id")) 
(for [x line] (clojure.string/replace x reint "int")) 

被评估(分为两个不同的惰性序列)然后被丢弃。 为了让它们影响 return 值,您必须捕获它们的 return 值并在下一轮替换中使用它们。 在这种情况下,我认为编写替换的最自然方法是线程宏 ->:

(for [x line] 
     (-> x 
         (clojure.string/replace reid "id")
         (clojure.string/replace reint "int")
         (clojure.string/replace readdop "addop")))

这会创建代码,将 reid 替换为 x 作为第一个参数,然后将 reint 替换为第一个参数的结果,依此类推。

或者,您可以使用 comp 组合匿名函数,如 (fn [s] (clojure.string/replace s reid "id")replace 的部分应用)。在命令式世界中,我们非常习惯 运行 宁多个 "bash the data in place" 的过程 - 在函数式世界中,您更经常将几个函数组合在一起以执行所有操作,然后 运行 结果。