2012-03-18 88 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使得它「實際上」執行副作用動作進行說明。

相關問題