我有一个原子:
(def test (atom {:james {:friends [:lucy :john :daisy]},
:lucy {:friends [:james :daisy]},
:daisy {:friends [:james :lucy]},
:john {:friends [:james]}}))
给予:詹姆斯作为一个论点,我需要迭代它的:朋友,并把每一个朋友:詹姆斯的朋友在一个列表。其结果肯定是这样的:
(:james :daisy :james :james :lucy)
到目前为止,这是我最大的努力:
(def user :james)
(def test2 (atom []))
(defn access
[user]
(get-in @test [user :friends]))
(doseq [connection (access user)]
(swap! test2 concat (access connection)))
@test2
我不认为使用另一个原子(test2)是最惯用的方法。
发布于 2019-06-08 12:23:44
没错,你不需要中间原子。
(def users (atom {:james {:friends [:lucy :john :daisy]},
:lucy {:friends [:james :daisy]},
:daisy {:friends [:james :lucy]},
:john {:friends [:james]}}))
(defn friends [dict level users]
(-> (fn [users] (mapcat #(get-in dict [% :friends]) users))
(iterate users)
(nth level)))
(friends @users 2 [:james])
发布于 2019-06-08 12:27:51
我只会在整个应用程序的“最高级”上使用原子。它们是可共享的、并发访问的、可变的、.数据(通常是全球性的)。
写出你所需要的函数,就像它们不知道你所能做到的那样。如果以纯函数结束,它会使测试变得更容易。如果您想要积累数据,那么对其进行格式化;在返回之前对计算步骤进行let
,等等。
所以这大概是我要走的路(注意,有一些方法可以剥去一只猫的皮,以使你的列表符合我的要求,我选择了地图):
(defn user
[users user-name]
(get users user-name))
(defn friends
[user]
(get user :friends))
(defn user-friends
[users user-name]
(some->> user-name (user users) (friends)))
(defn friends-friends
[users user-name]
(when-let [friend-names (user-friends users user-name)]
(mapcat (partial user-friends users) friend-names))) ; XXX replacement for the accumulating concat
最后,在您的测试或REPL中:
(let [users {:james {:friends [:lucy :john :daisy]}
:lucy {:friends [:james :daisy]}
:daisy {:friends [:james :lucy]}
:john {:friends [:james]}}]
(friends-friends users :james))
; => (:james :daisy :james :james :lucy)
发布于 2019-06-08 17:52:21
执行这类查询的另一种方法(或称为“间接”方式)是通过数据录,首先将嵌套的映射转换为事实:
(def friendship (mapcat (fn [[p {xs :friends}]]
(for [f xs]
[p :person/friend f]))
{:james {:friends [:lucy :john :daisy]},
:lucy {:friends [:james :daisy]},
:daisy {:friends [:james :lucy]},
:john {:friends [:james]}}))
;; =>
([:james :person/friend :lucy]
[:james :person/friend :john]
[:james :person/friend :daisy]
[:lucy :person/friend :james]
[:lucy :person/friend :daisy]
[:daisy :person/friend :james]
[:daisy :person/friend :lucy]
[:john :person/friend :james])
然后使用自定义规则(如friend
和friend-of-friend
)对事实执行Datalog查询。寻找:james
的朋友
(d/q '[:find [?f ...]
:where (friend-of-friend ?p ?f)
:in $ ?p %]
friendship
:james
'[[(friend ?p ?f)
[?p :person/friend ?f]]
[(friend-of-friend ?p ?f)
(friend ?p ?x)
(friend ?x ?f)
[(not= ?p ?f)]]])
;; => [:daisy :lucy]
哪里
[:find [?f ...]
:where (friend-of-friend ?p ?f)
:in $ ?p %]
是查询,friendship
是事实并映射到$
,:james
是查询的主题(映射到参数?p
),%
是定义为:
[[(friend ?p ?f) ; 1. What is a friend?
[?p :person/friend ?f]] ; ?p has an attribute :person/friend defined with ?f
[(friend-of-friend ?p ?f) ; 2. Friend of friend
(friend ?p ?x) ; ?p and ?x are friends (base on #1)
(friend ?x ?f) ; ?x and ?f are friends
[(not= ?p ?f)]]] ; ?p and ?f not same person
注意:上面的示例使用的是数据记录
https://stackoverflow.com/questions/56509648
复制