prega di non utilizzare nidificate def di. Non funziona, cosa pensi che faccia. la def è sempre globale! Per i locali si usa invece let. Mentre le funzioni della libreria sono piacevoli da sapere, ecco una versione che orchestra alcune funzionalità della programmazione funzionale in generale e del clojure in particolare.
(import 'java.io.FileWriter 'java.io.FileReader 'java.io.BufferedReader)
(defn translate-coords
Le docstrings possono essere interrogate nel REPL tramite (doc translate-coords). Funziona ad es. per tutte le funzioni principali. Quindi fornirne una è una buona idea.
"Reads coordinates from infile, translates them with the given
translator and writes the result to outfile."
Il traduttore è una funzione (forse anonima) che estrae la traduzione dal foglio caldaia circostante. Quindi possiamo riutilizzare queste funzioni con diverse regole di trasformazione. I suggerimenti del tipo qui evitano la riflessione per i costruttori.
[translator #^String infile #^String outfile]
Aprire i file. with-open si prenderà cura che i file siano chiusi quando il suo corpo è rimasto. Sia tramite normale "drop off the bottom" o sia tramite un'eccezione generata.
(with-open [in (BufferedReader. (FileReader. infile))
out (FileWriter. outfile)]
leghiamo il flusso *out*
temporaneamente al file di output. Quindi qualsiasi stampa all'interno della rilegatura verrà stampata sul file.
(binding [*out* out]
I mezzi map
: prendere il seq e applicare la funzione specificata per ogni elemento e restituire la seq dei risultati. Lo #()
è una notazione breve per una funzione anonima. Prende un argomento, che viene compilato allo %
. Il doseq
è fondamentalmente un ciclo sull'input. Dal momento che lo facciamo per gli effetti collaterali (ovvero la stampa su un file), doseq
è il costrutto corretto. Regola generale: map
: lazy => per risultato, doseq
: eager => per effetti collaterali.
(doseq [coords (map #(.split % ",") (line-seq in))]
println
prende cura per il \n
alla fine della linea. interpose
prende il seq e aggiunge il primo argomento (nel nostro caso "") tra i suoi elementi. (apply str [1 2 3])
equivale a (str 1 2 3)
ed è utile per costruire chiamate di funzione dinamicamente. Il ->>
è una macro relativamente nuova in clojure, che aiuta un po 'con la leggibilità. Significa "prendi il primo argomento e aggiungilo come ultimo elemento alla chiamata di funzione". Il dato ->>
è equivalente a: (println (apply str (interpose " " (translator coords))))
. (Modifica: Un'altra nota: dal momento che il separatore è \space
, potremmo scrivere altrettanto bene (apply println (translator coords))
, ma la versione interpose
consente di parametrizzare anche il separatore come abbiamo fatto con la funzione di traduttore, mentre la versione breve sarebbe stata cablata \space
.)
(->> (translator coords)
(interpose " ")
(apply str)
println)))))
(defn survey->cartography-format
"Translate coords in survey format to cartography format."
Qui usiamo la destrutturazione (notare il doppio [[]]
). Significa che l'argomento della funzione è qualcosa che può essere trasformato in un seq, ad es. un vettore o una lista. Associare il primo elemento a y
, il secondo a x
e così via.
[[y x z p]]
[p x y z])
(translate-coords survey->cartography-format "survey_coords.txt" "cartography_coords.txt")
Anche in questo caso meno mosso:
(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")
Spero che questo aiuti.
Modifica: per la lettura CSV probabilmente vuoi qualcosa come OpenCSV.
'my ($ x, $ y, $ z, $ p) = diviso /, /;' –
Buon punto - TIMTOWTDI. Grazie. –