Clojure的:造型简洁多对多的关系

问题描述 投票:2回答:2

由于我正在学习西班牙语,此刻我正在做一个死的简单快闪程序。

该应用程序有两个概念:

  1. 该卡本身。两个字符串,一个正面,一个在后面。此外,每个卡具有标记0-m的代码。例如。对于给定卡的标签可能是["spanish" "verb"]
  2. 配置文件。该配置文件存储两件事情:哪些卡是通过定义标签包括,和“知识得分”每张卡。

该应用程序的工作原理简单地通过选择一个配置文件来练习,让你在卡的正面与最低知识得分。当用户就绪时,它显示了背面。当用户输入他是否记得卡,修改该卡的知识得分。

对于任何人任何快闪程序之前使用它,这是超级平凡的东西。

我的问题是:如何在Clojure中惯用的模型呢?我在得到所面临的挑战是型材和卡之间的许多一对多的关系。

我可以创建一个状态图是这样的:

{:card-universe [
  {:front "Correr" :back "To run" :tags ["spanish" "verb"]}
  {:front "Querer" :back "To want" :tags ["spanish" "verb"]}
  {:front "La mesa" :back "The table" :tags ["spanish" "noun"]}]

 :profiles [
  {
   :name "Spanish verbs"
   :tags ["spanish" "verb"] 
   :cards [{:front "Correr" :back "To want" :score 7}
           {:front "Querer" :back "To want" :score 10}]
  }
  {
   :name "Spanish"
   :tags ["spanish"] 
   :cards [{:front "Correr" :back "To run" :score 8}
           {:front "Querer" :back "To want" :score 3}
           {:front "La mesa" :back "The table" :score 2}]
  }
 ]
}

这对我来说看起来很可笑。说我编辑卡,因为我犯了一个错误,那我就必须去通过所有的配置文件和更新它们。我可以对所有卡创建身份解决这个问题(有点),只是用它来指证,而不是:

{:card-universe [
  {:id "c1" :front "Correr" :back "To run" :tags ["spanish" "verb"]}
  {:id "c2" :front "Querer" :back "To want" :tags ["spanish" "verb"]}
  {:id "c3" :front "Mesa" :back "Table" :tags ["spanish" "noun"]}]

 :profiles [
  {
   :name "Spanish verbs"
   :tags ["spanish" "verb"] 
   :cards [{:id "c1" :score 7}
           {:id "c2" :score 10}]
  }
  {
   :name "Spanish words"
   :tags ["spanish"] 
   :cards [{:id "c1" :score 8}
           {:id "c2" :score 3}
           {:id "c3"  :score 2}]
  }
 ]
}

这也许是一个更好一点,但它仍然意味着,如果我在一个给定的标签添加更多的卡,我将不得不获取所有的牌。卡宇宙和:卡在我的个人资料之间基本上是一个外连接。

弹出下一个问题就是存储状态。我当然可以此状态下进行右只存储一个文件,但如果我是通过创建Web应用程序的SQL数据库将是我去将其扩展到多用户。在我心目中,我应该能全部达代码这一点,并存储在开始一个文件,以后还可以换出我如何存储数据,而无需触摸应用程序使用的功能的数据结构。

任何提示和经验将不胜感激!

我有一种感觉,该应用程序过于简单得到任何的好处Clojure的。特别是引入数据库时​​ - 这将基本上只是使这是一个CRUD应用程序。

clojure modeling
2个回答
2
投票

我可能会采取先东西拆开一点开始

(def card-data
  [{:id "c1" :front "Correr" :back "To run" :tags #{"spanish" "verb"}}
   {:id "c2" :front "Querer" :back "To want" :tags #{"spanish" "verb"}}
   {:id "c3" :front "Mesa" :back "Table" :tags #{"spanish" "noun"}}])

(defn spanish-words [cards]
  (filter #(-> % :tags (every? ["spanish"])) cards))

(defn spanish-verbs [cards]
  (filter #(-> % :tags (every? ["spanish" "verb"])) cards))

然后做一个用于测试的小原子分贝,与可以在其中存储状态的功能。你可以在以后你最终使用任何DB此功能抽象。

(def db (atom {}))

(defn remembered! [scores-db card]
  (swap! scores-db update (:id card) #(if % (inc %) 0)))

现在,我们可以对其进行测试。

#_user=> (->> card-data spanish-verbs first (remembered! db))
{"c1" 0}
#_user=> (->> card-data spanish-verbs second (remembered! db))
{"c1" 0, "c2" 0}
#_user=> (->> card-data spanish-verbs first (remembered! db))
{"c1" 1, "c2" 0}

这样可行。但是,我们可以进一步抽象出我们的过滤成select-tags功能。

(defn select-tags [cards & tags]
  (filter #(-> % :tags (every? (->> tags flatten (remove nil?)))) cards))

(defn spanish [cards & tags]
  (select-tags cards "spanish" tags))

(defn verbs [cards & tags]
  (select-tags cards "verb" tags))

#_user=> (spanish (verbs card-data))
({:id "c1", :front "Correr", :back "To run", :tags #{"verb" "spanish"}} {:id "c2", :front "Querer", :back "To want", :tags #{"verb" "spanish"}})
#_user=> (verbs (spanish card-data))
({:id "c1", :front "Correr", :back "To run", :tags #{"verb" "spanish"}} {:id "c2", :front "Querer", :back "To want", :tags #{"verb" "spanish"}})

而现在,我们只需撰写他们。

(defn spanish-verbs [cards & tags]
  ((comp spanish verbs) cards tags))
;; or (apply spanish cards "verb" tags)
;; or even (apply select-tags cards "verb" "spanish" tags)

#_user=> (->> card-data spanish-verbs first (remembered! db))
{"c1" 2, "c2" 0}

0
投票

如果你熟悉SQL,你应该适宜步行的SQL库和SQLite马上开始:http://walkable.gitlab.io您将大大受益于SQL的规范化中获益。步行的将仅仅通过几个按键使读取数据为树形结构微风,具有过滤。不要浪费你的时间打一场原子,域并不复杂,它不值得花时间做CRUD原型。

© www.soinside.com 2019 - 2024. All rights reserved.