Я работаю с инструментарием обмена сообщениями (это бывает Spread, но я не знаю, что детали имеют значение). Для получения сообщений из этого инструментария требуется некоторый шаблон:Преобразуйте этот вызов Clojure в ленивую последовательность
- Создайте соединение с демоном.
- Присоединиться к группе.
- Получалось одно или несколько сообщений.
- Оставьте группу.
- Отключить от демона.
После некоторых идиом, которые я видел, используемых elsewhere, я был в состоянии приготовить некоторые рабочие функции с использованием Spread в Java API и Interop формы 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
класс использует disconnect
вместо close
. Grr. Кроме того, я оставил некоторые макросы, которые не относятся к структурному вопрос здесь.)
Это работает достаточно хорошо. Я могу назвать приемно-сообщение внутри структуры, как:
(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 сверху: оставление группы и отключение от демона. Как я могу связать состояние соединения и группы с последовательностью и выполнить необходимый код очистки, когда последовательность больше не нужна?