2012-11-12 65 views
3

我已经无耻地举起了我发现的一个示例blogpost中的几乎所有代码(但现在似乎无法检索到),这些代码使用Java的套接字实现来维护简单的IRC连接。在条件范围内使用地图

虽然在这个例子中玩了一下,我遇到了一个问题,我想加入一系列的渠道。我的第一个想法是在服务器var上存储一个通道矢量,然后在模式匹配时对其进行解构。然而,这只是没有奏效。如果我将地图更改为写函数的裸调用,事情就可以正常工作。然而映射写功能似乎不起作用,我对此感到不知所措。有趣的是,如果我将地图调用复制并粘贴到运行活动连接的repl中,它就可以工作......所以这是因为这发生在cond的范围内?裁判有可能被指责吗?我只是闯入Clojure,所以我仍然非常想弄明白。

事不宜迟,下面的代码:

(ns irc 
    (:import (java.net Socket) 
      (java.io PrintWriter InputStreamReader BufferedReader))) 

    (def server {:server "irc.example.net" 
       :port 6667 
       :channels ["#a" "#b"]}) 
    (def client {:realname "Lambda Bot" :nick "lambdabot"}) 

    (declare conn-handler) 


    (defn in [a b] 
    (re-find (re-pattern a) b)) 


    (defn startswith [a b] 
    (in (str "^" a) b)) 


    (defn connect [server] 
    (let [socket (Socket. (:server server) (:port server)) 
      in (BufferedReader. (InputStreamReader. (.getInputStream socket))) 
      out (PrintWriter. (.getOutputStream socket)) 
      conn (ref {:in in :out out})] 
     (doto (Thread. #(conn-handler conn server)) (.start)) 
     conn)) 


    (defn write [conn msg] 
    (println msg) 
    (doto (:out @conn) 
     (.println (str msg "\r")) 
     (.flush))) 


    (defn conn-handler [conn server] 
    (while (nil? (:exit @conn)) 
     (let [msg (.readLine (:in @conn))] 
     (println msg) 
     (cond 
      (startswith "ERROR :Closing Link:" msg) 
      (dosync (alter conn merge {:exit true})) 
      (in " 001 " msg) 
      ;; this guy below doesn't seem to work at all 
      (map #(write conn (str "JOIN " %)) (:channels server)) 
      ;; this guy on the other hand seems to work fine 
      ;;(write conn (str "JOIN " (first (:channels server)))) 
      (startswith "PING" msg) 
      (write conn (str "PONG " (re-find #":.*" msg))))))) 


    (defn login [conn user] 
    (write conn (str "NICK " (:nick user))) 
    (write conn (str "USER " (:nick user) " 0 * :" (:realname user)))) 

要运行这个你可以直接电话咨询:(DEF IRC(连接服务器)),然后(登录IRC客户端)。任何帮助最受赞赏!谢谢。

回答

6

map是一种懒惰的操作,即直到需要才执行它。当从repl调用时,repl会导致它评估,因为它需要打印返回的值。

您可以使用doall强制懒操作的执行。

(doall (map ...)) 

更妙的是使用doseq而非mapmap用于将一组值转换为另一组值,并且doseq用于对一组值执行操作,以及您想要执行的操作。

(doseq [ch (:channels server)] 
    (write conn (str "JOIN " ch))) 
+1

'(doall(map ...))'偶尔会更容易编写,但我明白了你的观点。 – Cubic

+0

当然啊!由于地图是懒惰的,我应该已经意识到这里发生了什么,但我想我在思想上推迟到REPL的行为,而不考虑它会强制评估。谢谢你放纵我。 – maxcountryman