这是我与Clojure的第一次接触,因此我尝试编写简单的脚本,提供基于维基百科的翻译(欢迎任何评论/评论)
问题是:当我从翻译中删除(刷新)时,脚本输出nil而不是翻译的单词。为什么会这样?我显然遗漏了什么,但是什么? (println translations)得到的结果与flush相同(开头我尝试使用doseq / doall,但没有结果)
(使用Clojure 1.2并在逆时针方向上使用eclipse 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"))
答案 0 :(得分: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”。地图没有该键的元素,因此值为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
"Requin")
再次调用#'translations
值的地图。这次效果是查找nil
,“Requin”作为在地图中找不到nil
的情况下返回的默认值。
答案 1 :(得分: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>")))
let用于为let块中的表单创建本地绑定。使用def创建全局绑定(在当前命名空间中)。因此,基本上在执行退出代码之后,您可以在函数外部使用var transalations
,因为它是使用全局范围的def创建的。
我不确定flush与def有什么关系才能使它工作。可能对def工作有深入了解的人可以对此有所了解,这肯定是一件有趣的事情。
<强>更新强>
有趣的是,将函数体包装在do
中使其与def
一起使用而没有刷新,但这不是你应该做的事情。使用let
是首选方式。 do
用于执行一系列具有副作用的表达式,因此似乎def
是一种副作用表达式并使用do
或flush
使其“实际上” “执行副作用。