由于我正在学习西班牙语,此刻我正在做一个死的简单快闪程序。
该应用程序有两个概念:
["spanish" "verb"]
。该应用程序的工作原理很简单,只需选择要练习的个人资料,即可为您提供知识得分最低的卡片正面。当用户就绪时,它显示了背面。然后,用户输入是否他想起卡其改变该牌的知识分数。
对于任何其任何闪卡应用程序之前,使用时,该超级琐碎的东西。
我的问题是:如何在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应用程序。
答案 0 :(得分: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进行测试。你可以稍后抽象此功能无论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}
答案 1 :(得分:0)
如果您熟悉SQL,则应立即从Walkable sql库和sqlite开始: http://walkable.gitlab.io 您将从SQL的规范化中受益匪浅。 Walkable使得轻轻松松获取数据成为树状结构,只需按几次按键即可进行过滤。不要浪费时间与原子作战,领域并不复杂,花时间制作CRUD原型也不值得。