Skip to content

Instantly share code, notes, and snippets.

@masaedw
Created May 9, 2010 02:30
Show Gist options
  • Save masaedw/394909 to your computer and use it in GitHub Desktop.
Save masaedw/394909 to your computer and use it in GitHub Desktop.
;; 最後のデータが保存されちゃう問題についての再現コード
;;
;; ★やりたいこと
;;
;; サーバから次のようなデータ(¥n区切りの文字列)が送られてくる
;; aaa
;; bbb
;; ccc
;; end
;; ddd
;; end
;; eee
;; fff
;; ggg
;; end
;; アプリケーション的には end には何の意味もないが、
;; サーバは end を区切りとしてデータをまとめて送ってくる。
;;
;; ナイーブにサーバから送られてきたデータを逐次処理すると、
;; ((aaa bbb ccc end) (ddd end) (eee fff ggg end) ...)
;; というシーケンスになるので、これをflattenしたものを返すAPIを作りたい
;;
;; ★期待される動作
;;
;; end が送られた時点で、そのendまでの行について処理が行われる
;;
;; ★このスクリプトを使ったテスト方法
;;
;; myflatten を myflatten-good か myflatten-bad か選ぶ
;; ↓こんな感じ
;; (def myflatten myflatten-good)
;; ;;(def myflatten myflatten-bad)
;;
;; 起動
;; $ lein repl seq.clj
;;
;; 別ターミナルからtelnet接続
;; $ telnet localhost6666
;;
;; 適当な行を入力してendを入力する。
;;
;; myflatten-goodのときは、endを入力した時点で、そのendまでの内容がechoされる
;; myflatten-bad のときは、endを入力すると、その前のendまでの内容がechoされる
;;
;; なぜなんでしょうか???
;;
(use 'clojure.contrib.server-socket)
(import (java.io BufferedReader
InputStreamReader
PrintWriter
OutputStreamWriter))
(defn take-to-first
"Returns a lazy sequence of successive items from coll up to
and including the point at which it (pred item) returns true.
pred must be free of side-effects."
[pred coll]
(lazy-seq
(when-let [s (seq coll)]
(if-not (pred (first s))
(cons (first s) (take-to-first pred (rest s)))
(list (first s))))))
(defn partition-when
"Applies f to each value in coll, splitting it each time f returns
true. Returns a lazy seq of lazy seqs."
[f coll]
(lazy-seq
(when-let [s (seq coll)]
(let [run (take-to-first f s)
res (drop (count run) s)]
(cons run (partition-when f res))))))
;; なんかうまくいかない版
(defn myflatten-bad [lst]
(lazy-seq
(if (empty? lst) lst
(let [[x & xs] lst]
(if (seq? x)
(concat (myflatten-bad x) (myflatten-bad xs))
(cons x (myflatten-bad xs)))))))
;; うまくいく版
(defn myflatten-good [lst]
(lazy-seq
(if (empty? lst) lst
(let [x (first lst)
xs (rest lst)]
(if (seq? x)
(concat (myflatten-good x) (myflatten-good xs))
(cons x (myflatten-good xs)))))))
(def myflatten myflatten-good)
;;(def myflatten myflatten-bad)
(defn server-stream [sequence] (partition-when #(= "end" %) sequence))
(defn echo-server [in out]
(let [reader (BufferedReader. (InputStreamReader. in))
writer (PrintWriter. (OutputStreamWriter. out) true)]
(doseq [line (myflatten (server-stream (line-seq reader)))]
(.println writer (str "=> " line))
)))
(create-server 6666 echo-server)
@masaedw
Copy link
Author

masaedw commented May 9, 2010

clojure-1.2.0でないとそもそもうまく動きません。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment