2012-03-18 103 views
3

这是我用Clojure的第一次接触,所以我试着写简单的脚本,它提供了基于维基百科翻译(任何批评/评论,欢迎)为什么我必须在这段代码中使用(flush)?

的问题是:当我删除(齐平)翻译,脚本输出nil而不是翻译的单词。这是为什么?我明显错过了一些东西,但是什么? (的println翻译)给出相同的结果是齐平(在我与doseq/DOALL尝试开始,但没有效果)

(使用Clojure的1.2和3.7.2蚀逆时针方向测试)

的代码:

(ns wiki-translate 
    (:require [clojure.contrib.http.agent :as h]) 
) 

(defn get-url 
    ([lg term] (str "http://" lg ".wikipedia.org/wiki/" term)) 
) 

(defn fetch-url 
    ([url] (h/string (h/http-agent url))) 
) 

(defn get-translations 
    ([cnt] (apply sorted-map (flatten (for [s (re-seq #"(?i)interwiki-([^\"]+).*wiki\/([^\"]+)\".*/a>" cnt)] [(s 1) (s 2)]))))) 

(defn translate 
    [term src-lg tgt-lg] (
     (def translations (get-translations (fetch-url (get-url src-lg term))) ) 
     (flush) 
     (if (contains? translations tgt-lg) (get translations tgt-lg) "<NOT FOUND>")    
    )   
) 

(println (translate "Shark" "en" "fr")) 

回答

4

translate功能有括号的额外的水平,(flush)使得意外工作。而不(flush),将码是

((def translations (get-translations (fetch-url (get-url src-lg term)))) 
(if (contains? translations tgt-lg) (get translations tgt-lg) "<NOT FOUND>")) 

的Clojure根据its evaluation rules通过评估两个子形式和呼叫第一作为函数评估该形式。与子形式进行评价的形式变得

(#'translations 
"Requin") 

因为第一形式,返回所定义的VAR,并且它定义了在时间为所述第二形式中的查找成功。当你调用一个VAR的功能,the call is delegated to the value of the Var,这是一张地图,而且由于map implements function call as look-up,效果是查找“Requin”在地图上。该地图没有包含该键的元素,因此该值为零。

随着之间,相同的过程发生在加入的(flush)

((def translations (get-translations (fetch-url (get-url src-lg term)))) 
(flush) 
(if (contains? translations tgt-lg) (get translations tgt-lg) "<NOT FOUND>")) 

首先计算到

(#'translations 
nil 
"Requin") 

,并再次向地图是#'translations值被调用。这次效果是查找nil,并且在地图中未找到nil的情况下将“Requin”作为默认值返回。

3

您需要使用let而非def的转换函数内部:

(defn translate 
    [term src-lg tgt-lg] 
    (let [translations (get-translations (fetch-url (get-url src-lg term)))] 
     (if (contains? translations tgt-lg) (get translations tgt-lg) "<NOT FOUND>"))) 

让利是用于ŧ o为let块中的表单创建本地绑定。使用def创建一个全局绑定(在当前命名空间中)。所以基本上在执行完退出代码之后,你可以在函数的外部使用var transalations,因为它是在全局范围内使用def创建的。

我并不完全相信平与DEF做,使其工作。可能有人对def的工作方式有深入的了解,这可能会对此有所了解,那肯定是一件有趣的事情。

UPDATE:

有趣的是包装函数体中do使得它与def工作,无需刷新,但是这是不是你应该做的。使用let是首选的方法。 do用于执行一系列表达的有副作用,因此似乎def是一种副作用表达和使用doflush使得它“实际上”执行副作用动作进行说明。

相关问题