【问题标题】:Transform this Clojure call into a lazy sequence将此 Clojure 调用转换为惰性序列
【发布时间】:2009-10-27 02:13:01
【问题描述】:

我正在使用消息传递工具包(它恰好是 Spread,但我不知道细节是否重要)。从这个工具包接收消息需要一些样板:

  1. 创建与守护程序的连接。
  2. 加入一个小组。
  3. 接收一条或多条消息。
  4. 离开小组。
  5. 断开与守护程序的连接。

按照我见过的一些习惯用法elsewhere,我能够使用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 类使用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 sequence lazy-evaluation


    【解决方案1】:

    This 文章描述了如何使用 clojure-contrib 填充队列来做到这一点。关于清理 - 关于填充队列的巧妙之处在于,您可以提供一个阻塞函数,如果出现错误或达到某些条件,它会自行清理。您还可以持有对资源的引用以在外部控制它。该序列将终止。因此,根据您的语义要求,您必须选择适合的策略。

    【讨论】:

      【解决方案2】:

      试试这个:

      (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) 中抛出的任何异常也会终止列表。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-10-25
        • 2011-06-26
        • 2010-12-08
        • 2014-06-17
        • 1970-01-01
        • 1970-01-01
        • 2012-06-16
        • 1970-01-01
        相关资源
        最近更新 更多