このClojure呼び出しを遅延シーケンスに変換します
-
06-07-2019 - |
質問
メッセージングツールキットを使用しています(スプレッドですが、それがわかりません詳細が重要です)。このツールキットからメッセージを受信するには、いくつかの定型文が必要です。
- デーモンへの接続を作成します。
- グループに参加します。
- 1つ以上のメッセージを受信します。
- グループを去る。
- デーモンから切断します。
他の場所で使用したイディオムに続いて、料理をすることができましたSpreadのJava APIとClojureの相互運用フォームを使用したいくつかの機能:
(defn connect-to-daemon
"Open a connection"
[daemon-spec]
(let [connection (SpreadConnection.)
{:keys [host port user]} daemon-spec]
(doto connection
(.connect (InetAddress/getByName host) port user false false))))
(defn join-group
"Join a group on a connection"
[cxn group-name]
(doto (SpreadGroup.)
(.join cxn group-name)))
(defn with-daemon*
"Execute a function with a connection to the specified daemon"
[daemon-spec func]
(let [daemon (merge *spread-daemon* daemon-spec)
cxn (connect-to-daemon daemon-spec)]
(try
(binding [*spread-daemon* (assoc daemon :connection cxn)]
(func))
(finally
(.disconnect cxn)))))
(defn with-group*
"Execute a function while joined to a group"
[group-name func]
(let [cxn (:connection *spread-daemon*)
grp (join-group cxn group-name)]
(try
(binding [*spread-group* grp]
(func))
(finally
(.leave grp)))))
(defn receive-message
"Receive a single message. If none are available, this will block indefinitely."
[]
(let [cxn (:connection *spread-daemon*)]
(.receive cxn)))
(基本的には with-open
と同じイディオム、 SpreadConnection
クラスは close
disconnect を使用するだけです。 >。Grr。また、ここでは構造的な質問に関係のないマクロをいくつか省略しました。)
これは十分に機能します。次のような構造の内部からreceive-messageを呼び出すことができます。
(with-daemon {:host "localhost" :port 4803}
(with-group "aGroup"
(... looping ...
(let [msg (receive-message)]
...))))
receive-message
がメッセージを生成する無限のレイジーシーケンスである場合、使用するほうがクリーンになると思います。したがって、グループに参加してメッセージを取得する場合、呼び出しコードは次のようになります。
(def message-seq (messages-from {:host "localhost" :port 4803} "aGroup"))
(take 5 message-seq)
クリーンアップせずに遅延シーケンスの例をたくさん見ましたが、それほど難しくはありません。キャッチは、上記のステップ4と5です。グループから離脱し、デーモンから切断します。接続の状態をグループ化し、シーケンスにグループ化し、シーケンスが不要になったときに必要なクリーンアップコードを実行するにはどうすればよいですか
解決
このの記事では、 clojure-contrib fill-queueを使用して正確にそれを行う方法。クリーンアップについて-fill-queueの素晴らしい点は、エラーが発生した場合や何らかの条件に達した場合にクリーンアップするブロッキング関数を提供できることです。リソースへの参照を保持して、外部から制御することもできます。シーケンスは終了します。したがって、セマンティック要件に応じて、適合する戦略を選択する必要があります。
他のヒント
これを試してください:
(ns your-namespace
(:use clojure.contrib.seq-utils))
(defn messages-from [daemon-spec group-name]
(let [cnx (connect-to-deamon daemon-spec))
group (connect-to-group cnx group-name)]
(fill-queue (fn [fill]
(if done?
(do
(.leave group)
(.disconnect cnx)
(throw (RuntimeException. "Finished messages"))
(fill (.receive cnx))))))
設定完了?リストを終了する場合はtrueに設定します。また、スローされた例外(.receive cnx)もリストを終了します。