【问题标题】:Swap! value doesn't resolve交换!价值无法解决
【发布时间】:2017-06-07 16:10:25
【问题描述】:

在解析 xml 文件时,我将值标准化并通过交换保存它们!变成一个原子。另外我建了一棵树来反映原始结构。

当我调用该函数时,它只返回一部分数据,而不是标准化值。当我取消引用原子时,数据已完全写入。

这里是代码的一部分,这似乎对该行为至关重要。

(defn normalize-values
  "Save the dataset to the atom and returns the reference"
  [tour-id key value]
  (swap! db assoc-in [tour-id (query-key key :name) value] {:title value})
  {key [(query-key key) value]})


(defn extract-tags
  "Differs between unique and normalizable values"
  [node tour-id]
  (let [data (zip/xml-zip node)
        key (:tag node)
        value (zx/xml1-> data key zx/text)
        res (if (some #{key} [:sound :map :video :creator])
              (normalize-values tour-id key value)
              {key value})]
    res))

(defn panorama->map
  "Creates a panorama map from the xml data"
  [node tour-id]
  (let [xml-node (zip/node node)
        tag-values (into {} (map #(extract-tags % tour-id) (:content xml-node)))]
    (merge tag-values
           {:id     (get-file-id (:file tag-values))
            :hidden (read-string (get-in xml-node [:attrs :hidden]))})))


(defn menu->map
  "Loops over the xml tree and builds the structure"
  [tour-id menu]
  (for [entry menu]
    (let [children (childs-of-child entry)]
      (if (not-empty children)
        (let [{:keys [id] :as category-map} (category->map entry)]
          (swap! db assoc-in [tour-id (query-key :categorie :id) id] category-map)
          {:loc      [:categories/by-id id]
           :children (menu->map tour-id children)})

        (let [{:keys [id] :as panorama-map} (panorama->map entry tour-id)]
          (swap! db assoc-in [tour-id (query-key :pano :id) id] panorama-map)

          {:loc [:panos/by-id id]})))))

(defn parse-menu
  "Starting function which resets the db and saves all data to the atom "
  [path id]
  (swap! db dissoc id)
  (logging/debug "Parse Menu: " path)

  (let [xml (xml->map path)
        menu-data (menu->map id (:content xml))]

    (swap! db assoc-in [id :title] (tour-title xml))
    (swap! db assoc-in [id :tree] menu-data)

    (get @db id)))

我怎样才能意识到原子被正确解析了?

【问题讨论】:

  • 您能否更清楚地了解究竟哪里出了问题,以及您在调试时看到了什么?另外,能发一下xml->map的出处吗?
  • 我建议始终使用构造 (vec (for ...)) 在除极少数情况外的所有情况下禁用惰性结果。在 Tupelo 库中,我为此目的定义了 forv(类似于 clojure.core 中的 mapv)。
  • 谢谢,vec 的提示带来了解决方案。我忘了,那个 for 也很懒。

标签: xml clojure lazy-evaluation


【解决方案1】:

for 是懒惰的,在你意识到它产生的序列的元素之前,它不会执行你潜入它体内的副作用。您的描述“当我取消引用原子时,数据已完全写入。”不清楚,但我怀疑你的意思是你在 repl 中取消它,导致它的值被打印,这会强制嵌入其中的惰性序列,从而导致它们的副作用运行。

【讨论】:

    【解决方案2】:

    正如@Alan Thompson 评论的那样,错误的来源是惰性评估。在 (for) 循环之前添加 (vec) 后,问题就消失了。

    (defn menu->map
      "Loops over the xml tree and builds the structure"
      [tour-id menu]
    
      (vec    ;;forcing the evaluation of the loop
    
       (for [entry menu]
         (let [children (childs-of-child entry)]
           (if (not-empty children)
             (let [{:keys [id] :as category-map} (category->map entry)]
               (swap! db assoc-in [tour-id (query-key :categorie :id) id] category-map)
               {:loc      [:categories/by-id id]
                :children (menu->map tour-id children)})
    
             (let [{:keys [id] :as panorama-map} (panorama->map entry tour-id)]
               (swap! db assoc-in [tour-id (query-key :pano :id) id] panorama-map)
    
               {:loc [:panos/by-id id]}))))))
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-05-06
      • 2017-03-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-06-03
      相关资源
      最近更新 更多