2015-11-16 2 views
1

Итак, я знаю, что это не лучший метод решения этой проблемы, но я пытаюсь просмотреть список строк из входного файла, который в конечном итоге является выражением. У меня есть список выражений, и каждое выражение имеет собственный список благодаря функции split-the-list. Следующим шагом будет замена символов на id, ints с int и + или - с addop. У меня есть регулярные выражения, чтобы определить, соответствуют ли мои символы любым из них, но когда я пытаюсь их заменить, я могу получить только последний цикл цикла, который я вызываю, чтобы оставить какие-либо длительные результаты. Я знаю, что это значит, так это то, как работает функциональное программирование, но я не могу окунуться в трассировку этой программы и как заменить каждый отдельный тип ввода и сохранить результаты в одном списке.Новичок в clojure: токенизация списков разных символов

(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))) 

И, как вы, вероятно, можете сказать, я довольно новичок в функциональном программировании, поэтому любые советы приветствуются!

+0

Почему вы используете все эти 'in'? В коде нет ничего общего. –

ответ

2

Вы используете блок do, который оценивает несколько выражений (обычно для побочных эффектов), а затем возвращает последний. Вы не видите его, потому что fn (и, следовательно, defn) неявно содержат его. Таким образом, линии

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

оцениваются (в двух разных ленивых последовательностях), а затем выбрасываются. Чтобы они повлияли на возвращаемое значение, вы должны зафиксировать их возвращаемые значения и использовать их в следующем раунде заметок. В этом случае, я думаю, что самый естественный способ скомпоновать замены является резьб макро ->:

(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). В императивном мире мы привыкли использовать несколько процедур, которые «подталкивают данные на месте» - в функциональном мире вы чаще объединяете несколько функций для выполнения всех операций, а затем запускаете результат.

+0

Большое вам спасибо, это облегчает жизнь. –

Смежные вопросы