Clojure > Archives > 2010/04/19

2010/04/19 15:04:31 UTCmasa_edw
#
(use clojure.contrib.server-socket)
(import (java.io BufferedReader
                 InputStreamReader
                 PrintWriter
                 OutputStreamWriter))

(defn hoge [in out]
  (let [reader (BufferedReader. (InputStreamReader. in))
        writer (PrintWriter. (OutputStreamWriter. out))]
    (doall
     (for [line (line-seq reader)]
       (do
         (.println writer line)
         (.flush writer))))))

(create-server 6666 hoge)
#
まだ言ってるのかって感じですが、clojureハッカソンのときにはまってた問題を短いコードで再現させました。
#
echoサーバを作ろうと思ってこういうコードを書くと、一個前の行が出力されるんですが、何が原因なんでしょうか?
2010/04/19 15:55:40 UTCfatrow
#
何が原因なんですか?
2010/04/19 18:36:49 UTCfatrow
#
分かった!line-seq の中の lazy-seq の位置が問題ですね。
user> (use 'clojure.contrib.repl-utils)
user> (source line-seq)
(defn line-seq
  "Returns the lines of text from rdr as a lazy sequence of strings.
  rdr must implement java.io.BufferedReader."
  [#^java.io.BufferedReader rdr]
  (let [line  (. rdr (readLine))]
    (when line
      (lazy-seq (cons line (line-seq rdr))))))

lazy-seq は内側の計算は遅延してくれるけど、外側の (readLine) は遅延してくれない。
なので常に一個余計に readLine されちゃう。
  (let [line  (. rdr (readLine))] も lazy-seq に包んじゃえばOK.