代码之家  ›  专栏  ›  技术社区  ›  mtnygard

将此Clojure调用转换为一个惰性序列

  •  2
  • mtnygard  · 技术社区  · 15 年前

    我正在使用一个消息传递工具包 Spread 但我不知道细节很重要)。从该工具包接收消息需要一些样板文件:

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

    遵循我见过的一些习语 elsewhere 我可以用扩展的Java API和Culjress的互操作形式来编写一些工作函数:

    (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:离开组并断开与守护进程的连接。如何将连接状态和组绑定到序列中 当不再需要序列时运行必要的清理代码?

    2 回复  |  直到 14 年前
        1
  •  6
  •   Timothy Pratley    15 年前

    This 本文描述了如何使用clojure-contrib填充队列来精确地实现这一点。关于清除——关于填充队列的一个简洁的事情是,您可以提供一个阻塞函数,在出现错误或达到某个条件时自动清除。您还可以保存对资源的引用,以对其进行外部控制。序列将终止。因此,根据您的语义需求,您必须选择适合的策略。

        2
  •  3
  •   Eric Normand    15 年前

    试试这个:

    (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)中引发的任何异常也将终止列表。