Почему я должен использовать (очистить) в этом коде? - PullRequest
3 голосов
/ 18 марта 2012

Это мой первый контакт с Clojure, поэтому я попытался написать простой скрипт, который обеспечивает перевод, основанный на википедии (приветствуются любые критики / комментарии)

Проблема: при удалении (сброс)из перевод , скрипт выводит ноль вместо переведенного слова. Почему это так?Я явно что-то упускаю, но что?(println translations) дает тот же результат, что и flush (вначале я пытался с доза q / 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"))

Ответы [ 2 ]

4 голосов
/ 18 марта 2012

Функция 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 оценивает эту форму в соответствии с ее правилами оценки , оценивая две подформы и вызывая первую как функцию.С оцененными подформами форма становится

(#'translations
 "Requin")

, потому что первая форма возвращает определяемый Var и определяет его вовремя, чтобы вторая форма преуспела в поиске.Когда вы вызываете Var как функцию, вызов делегируется значению Var , которое является картой, и, поскольку map реализует вызов функции как поиск , эффектэто посмотреть «Реквина» на карте.На карте нет элемента с этим ключом, поэтому значение равно 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 не найден на карте.

3 голосов
/ 18 марта 2012

Вам нужно использовать 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, может пролить свет на это, и это было бы интересно узнать наверняка.

UPDATE:

Интересно, что обёртывание тела функции в do заставляет его работать с def без сброса, но это не то, что вы должны делать. Использование let является предпочтительным способом. do используется для выполнения серии выражений, которые имеют побочные эффекты, поэтому кажется, что def является своего рода выражением побочного эффекта, а использование do или flush заставляет его «фактически» выполнять операцию побочного эффекта.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...