将此Clojure调用转换为惰性序列
我正在使用一个消息传递工具包(它碰巧是,但我不知道细节是否重要)。从该工具包接收消息需要一些样板文件:将此Clojure调用转换为惰性序列,clojure,sequence,lazy-evaluation,Clojure,Sequence,Lazy Evaluation,我正在使用一个消息传递工具包(它碰巧是,但我不知道细节是否重要)。从该工具包接收消息需要一些样板文件: 创建到守护进程的连接 加入一个团体 接收一条或多条消息 离开小组 断开与守护进程的连接 按照我见过的一些习惯用法,我能够使用Spread的Java API和Clojure的interop表单编写一些工作函数: (defn connect-to-daemon "Open a connection" [daemon-spec] (let [connection (SpreadConne
(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)))
(基本上与使用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步:离开组并断开与守护进程的连接。如何将连接和组的状态绑定到序列中,并在不再需要序列时运行必要的清理代码?文章介绍了如何使用clojure contrib 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)中引发的任何异常也将终止列表