Clojure 为什么我必须在这段代码中使用(flush)?
这是我第一次接触Clojure,所以我试着写一个简单的脚本,提供基于维基百科的翻译(欢迎评论) 问题是:当我从translate中删除(flush)时,脚本输出nil而不是translated word。为什么?我显然错过了什么,但是什么呢?(println translations)给出了与flush相同的结果(起初我尝试使用doseq/doall,但没有结果) (使用Clojure 1.2并在eclipse 3.7.2中以逆时针方向进行测试) 守则:Clojure 为什么我必须在这段代码中使用(flush)?,clojure,Clojure,这是我第一次接触Clojure,所以我试着写一个简单的脚本,提供基于维基百科的翻译(欢迎评论) 问题是:当我从translate中删除(flush)时,脚本输出nil而不是translated word。为什么?我显然错过了什么,但是什么呢?(println translations)给出了与flush相同的结果(起初我尝试使用doseq/doall,但没有结果) (使用Clojure 1.2并在eclipse 3.7.2中以逆时针方向进行测试) 守则: (ns wiki-translate
(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"))
(ns维基翻译)
(:require[clojure.contrib.http.agent:as h])
)
(defn获取url
([lg术语](str“http://”lg.wikipedia.org/wiki/“术语))
)
(defn获取url)
([url](h/string(h/http代理url)))
)
(defn获取翻译
([cnt](应用排序地图(展平(用于[s(re-seq#“(?i)interwiki-([^\“]+).*wiki\/([^\“]+)\”*/a>“cnt)][(S1)(S2)])))
(defn翻译
[术语src lg tgt lg](
(def翻译(获取翻译(获取url(获取url src lg term)))
(齐平)
(如果(包含?翻译tgt lg)(获取翻译tgt lg)”)
)
)
(println(翻译为“Shark”“en”“fr”))
您需要在translate函数中使用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>")))
(defn翻译)
[术语src lg tgt lg]
(let[翻译(获取翻译(获取url(获取url src lg term)))]
(如果(包含?翻译tgt lg)(获取翻译tgt lg)”)
let用于为let块中的表单创建本地绑定。使用def会创建全局绑定(在当前命名空间中)。因此,基本上,在执行现有代码后,可以在函数外部使用vartranslations
,因为它是在全局范围内使用def创建的
我不太清楚flush与def有什么关系才能使其正常工作。也许有人对def的工作原理有深入的了解,可以对此有所了解,这肯定是一件有趣的事情
更新:
有趣的是,将函数体包装在
do
中可以使其与def
一起工作而不使用flush,但这不是您应该做的事情。使用let
是首选方法。do
用于执行一系列具有副作用的表达式,因此似乎def
是一种副作用表达式使用do
或flush
可以“实际”执行副作用操作。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>"))
因为第一个表单返回要定义的Var,并及时定义它,以便第二个表单在查找中成功。当您将Var作为一个函数调用时,这是一个映射,因此,效果是在映射中查找“Requin”。映射没有带有该键的元素,因此值为nil
将(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
,如果在映射中找不到nil
,则返回“Requin”作为默认值
((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")