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" 的过程 - 在函数式世界中,您更经常将几个函数组合在一起以执行所有操作,然后 运行 结果。
所以我知道这不是解决此问题的最佳方法,但我正在尝试遍历输入文件中的行列表,这些行最终成为表达式。我有一个表达式列表,由于拆分列表功能,每个表达式都有自己的列表。我的下一步是用 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" 的过程 - 在函数式世界中,您更经常将几个函数组合在一起以执行所有操作,然后 运行 结果。