我是clojure的新手,我正在通过从Practical Common Lisp重新创建cd项目来学习。我在使用where'子句'实现更新功能时遇到了麻烦。选择。执行(更新(其中:艺术家" AC / DC"):评级10)导致我的数据库被吹走,只返回一个空列表。这是我的代码:
(defn where [& {:keys [title artist genre rating]}]
(fn [cd]
(and
(if title (= (get cd :title) title) true)
(if artist (= (get cd :artist) artist) true)
(if genre (= (get cd :genre) genre) true)
(if rating (= (get cd :rating) rating) true))))
(defn update [selector-fn & {:keys [title artist genre rating]}]
(def ^:dynamic *db*
(map (fn [row]
(when (apply selector-fn row)
(if title (def row (assoc-in row [:title] title)))
(if artist (def row (assoc-in row [:artist] artist)))
(if genre (def row (assoc-in row [:genre] genre)))
(if rating (def row (assoc-in row [:rating] rating))))
row)
*db*)))
我已将每张CD实现为哈希映射:
(defn make-cd [title artist genre rating]
{:title title
:artist artist
:genre genre
:rating rating
})
所以我认为我对assoc-in的使用是正确的。关于我做错的任何想法都将不胜感激。
感谢...
MZ
确定。根据Arthur的评论,这里是我现在对更新功能所做的:
(defn update [selector-fn & {:keys [title artist genre rating]}]
(map (fn [row]
(when (apply selector-fn row)
(-> row
(#(if title (assoc-in % [:title] title) %))
(#(if artist (assoc-in % [:artist] artist) %))
(#(if genre (assoc-in % [:genre] genre) %))
(#(if rating (assoc-in % [:rating] rating) %)))))
*db*))
我认为我还需要map
表单,因为我需要迭代*db*
。我不想更改*db*
中所有CD的评分,只是艺术家AC / DC的评分。所以map
将遍历每个cd(将其绑定到row
),然后调用where
函数以查看标题是否匹配。如果是这样,那么它将返回true,允许更新评级。
不幸的是,这仍然无效。
ArityException Wrong number of args (4) passed to: core$where$fn clojure.lang.AFn.throwArity (AFn.java:437)
答案 0 :(得分:3)
在函数中使用def
很少有预期的结果(并且不是线程安全的)。因为每个操作都采用一个映射,更改它并返回更改后的映射,所以您可以将每个操作进入下一个操作,以便最后一个操作的返回值是所有更改的效果。这种模式在Clojure中非常常见,因此有一个两个字符宏可以非常方便地完成它:
user> (-> {:a {:k 1} :b {:k 2} :c {:k 3}}
(assoc-in [:a :k] 8)
(assoc-in [:b :k] 9))
{:a {:k 8}, :c {:k 3}, :b {:k 9}}
“线程优先”maco ->
只是将每个表达式作为第一个参数插入到下一个表达式中。所以上面的表达式(带有一些艺术许可证)扩展到:
(assoc-in (assoc-in {:a {:k 1} :b {:k 2} :c {:k 3}} [:a :k] 8) [:b :k] 9))
在您的上下文中,这看起来像这样:
(-> row
(#(if title (assoc-in % [:title] title) %))
(#(if artist (assoc-in % [:artist] artist) %))
(#(if genre (assoc-in % [:genre] genre) %))
(#(if rating (assoc-in % [:rating] rating) %)))
每一行创建一个函数,该函数返回其参数的更改版本或不更改它,然后调用它。 row
参数将插入到行尾的两个parens之间。如果这不具有视觉吸引力,您可以使用defn
为功能命名,并仅列出->
来电中的名称。
答案 1 :(得分:0)
在我看来,你试图在更新函数中改变行,但你真正在做的是在每一步重新定义它。
但是你的map
函数没有返回新行。
我希望reduce
行本身在指定时更改属性。