Code Aquarium

minazoko's blog -*- 水底のブログ -*-

Clojure-Pyでファイルリード

●テキストファイルを読む

行単位で遅延リードしてテキスト処理。
ファイル終了判定は空文字列との一致判定。pythonのreadlineは行末に改行をくっつけたまま読み込むのでファイル終端でなけれな空行でも空文字列にはならない。

(defn repeatedly [f]
  (lazy-seq (cons (f) (repeatedly f))))

(defn file-content-seq [f]
  (->> (repeatedly #(.readline f))
       (take-while #(not= "" %))))

(defn proc-line [line]
  (format "[%s]" (.rstrip line)))

(defn main [filename]
  (with-open [f (py/open filename)]
    (doseq [line (file-content-seq f)]
      (println (proc-line line)))))

(main (first *command-line-args*)) 

repeatedlyがなくて「おや?」と思ったけど、untranslated.cljに入ってた。他にもかなり重要そうな基本フォームが入ってるけどそんなんで大丈夫なの?

CSVファイルを読む

Pythonは標準ライブラリにcsvモジュールが用意されています。

(require 'csv)

(defn iterable->seq [iterable]
  (lazy-seq
   (try (cons (.next iterable)
              (iterable->seq iterable))
        (catch py/StopIteration _ nil))))

(defn proc-row [row]
  (.join "<>" row))

(defn main [filename]
  (with-open [f (py/open filename)]
    (doseq [row (-> (csv/reader f) iterable->seq)]
      (println (proc-row row)))))

(main (first *command-line-args*)) 

Pythonのfor-eachループはnextメソッドで値を取得し、StopIterationという例外throwが終了を表す。このループ終了仕様はちょっと厄介かもしれない。Pythonでは構文で例外を隠しているのだろうけど、Clojure-Pyでは明示的に例外処理しなきゃならない。
.nextの度にtry..catchを仕掛けるというのはパフォーマンス的に大丈夫なのかな?
Clojure-Pyではジェネレータ(types.GeneratorType)はSeqableをextendしていてseq関数でシーケンス化できる。でもイテレータクラスは継承無しのダックタイピングなのでジェネリックには扱えないような? ...このへん、もうすこし調べたい。