Пожалуйста, не используйте вложенные определения. Это не так, как вы думаете. def всегда глобален! Для местных жителей используйте вместо этого пусть. Хотя функции библиотеки приятно знать, здесь есть версия, в которой описаны некоторые функции функционального программирования в целом и clojure в частности.
(import 'java.io.FileWriter 'java.io.FileReader 'java.io.BufferedReader)
(defn translate-coords
Строки документации могут быть запрошены в REPL через (doc translate -ordins). Работает например для всех основных функций. Так что снабжение - хорошая идея.
"Reads coordinates from infile, translates them with the given
translator and writes the result to outfile."
переводчик - это (возможно, анонимная) функция, которая извлекает перевод из окружающего шаблона. Таким образом, мы можем повторно использовать эти функции с различными правилами преобразования. Здесь подсказки типов избегают отражения для конструкторов.
[translator #^String infile #^String outfile]
Откройте файлы. with-open позаботится о том, чтобы файлы были закрыты, когда его тело осталось. Будь то через обычное «падение с дна» или через исключение.
(with-open [in (BufferedReader. (FileReader. infile))
out (FileWriter. outfile)]
Мы временно связываем поток *out*
с выходным файлом. Так что любая печать внутри переплета будет печататься в файл.
(binding [*out* out]
map
означает: возьмите seq и примените данную функцию к каждому элементу и верните seq результатов. #()
является сокращенной записью для анонимной функции. Требуется один аргумент, который заполняется в %
. doseq
- это в основном цикл ввода. Поскольку мы делаем это для побочных эффектов (а именно, для печати в файл), doseq
- правильная конструкция. Основное правило: map
: ленивый => для результата, doseq
: нетерпеливый => для побочных эффектов.
(doseq [coords (map #(.split % ",") (line-seq in))]
println
заботится о \n
в конце строки. interpose
берет seq и добавляет первый аргумент (в нашем случае "") между его элементами. (apply str [1 2 3])
эквивалентно (str 1 2 3)
и полезно для динамического создания вызовов функций. ->>
- относительно новый макрос в clojure, который немного помогает с удобочитаемостью. Это означает «взять первый аргумент и добавить его как последний элемент к вызову функции». Указанное ->>
эквивалентно: (println (apply str (interpose " " (translator coords))))
. (Редактировать: еще одно примечание: поскольку разделитель \space
, мы могли бы также написать (apply println (translator coords))
, но версия interpose
позволяет также параметризовать разделитель, как мы делали с функцией переводчика, в то время как у короткой версии hardwire \space
.)
(->> (translator coords)
(interpose " ")
(apply str)
println)))))
(defn survey->cartography-format
"Translate coords in survey format to cartography format."
Здесь мы используем деструктурирование (обратите внимание на двойное [[]]
). Это означает, что аргумент функции - это то, что можно превратить в последовательность, например. вектор или список. Привязать первый элемент к y
, второй к x
и т. Д.
[[y x z p]]
[p x y z])
(translate-coords survey->cartography-format "survey_coords.txt" "cartography_coords.txt")
Здесь опять менее изменчиво:
(import 'java.io.FileWriter 'java.io.FileReader 'java.io.BufferedReader)
(defn translate-coords
"Reads coordinates from infile, translates them with the given
translator and writes the result to outfile."
[translator #^String infile #^String outfile]
(with-open [in (BufferedReader. (FileReader. infile))
out (FileWriter. outfile)]
(binding [*out* out]
(doseq [coords (map #(.split % ",") (line-seq in))]
(->> (translator coords)
(interpose " ")
(apply str)
println)))))
(defn survey->cartography-format
"Translate coords in survey format to cartography format."
[[y x z p]]
[p x y z])
(translate-coords survey->cartography-format "survey_coords.txt" "cartography_coords.txt")
Надеюсь, это поможет.
Edit: для чтения CSV вы, вероятно, хотите что-то вроде OpenCSV.