Clojure:建模简单的多对多关系
因为我正在学习西班牙语,所以我正在制作一个非常简单的Flashcard应用程序 该应用程序有两个概念:Clojure:建模简单的多对多关系,clojure,modeling,Clojure,Modeling,因为我正在学习西班牙语,所以我正在制作一个非常简单的Flashcard应用程序 该应用程序有两个概念: 卡片本身。两根绳子,一根在前面,一根在后面。此外,每张卡都有0-m标签。例如,给定卡片的标签可以是[“西班牙语”动词] 简介。配置文件存储两件事:通过定义标签包括哪些卡,以及每张卡的“知识分数” 该应用程序的工作原理很简单,只需选择一个个人资料进行练习,就可以在卡片的正面获得最低的知识分数。当用户准备好时,它会显示背面。然后,用户输入他是否记得修改该卡知识分数的卡 对于以前使用过任何Flash
[“西班牙语”动词]
{: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}]
}
]
}
这可能会好一点,但这仍然意味着如果我在一个给定的标签中添加更多的卡,我将不得不获取所有的卡。基本上是my:card universe和配置文件中的:cards之间的外部连接
下一个弹出的问题是存储状态。当然,我可以将这种状态直接存储到一个文件中,但如果我要通过创建web应用程序将其扩展到多用户,那么SQL数据库将是我的目标。在我看来,我应该能够在开始时将所有这些编码并存储到一个文件中,然后能够在不涉及应用程序用于运行的数据结构的情况下交换存储数据的方式
任何提示和经验都将不胜感激
我有一种感觉,应用程序太简单,无法获得Clojure的任何好处。特别是在引入数据库时——这基本上就是一个CRUD应用程序。我可能会先把东西拆开一点
(def卡数据
[{:id“c1”:前面的“Correr”:后面的“To run”:tags{“西班牙语”“动词”}
{:id“c2”:前面的“queryr”:后面的“To want”:标记{“西班牙语”“动词”}
{:id“c3”:前面的“Mesa”:后面的“Table”:标记#{“西班牙语”“名词”}}])
(defn西班牙语单词[卡片]
(过滤卡(>%:tags(每?[“西班牙语”]))
(defn西班牙语动词[卡片]
(过滤卡(>%:tags(每?[“西班牙语”动词]))
然后制作一个用于测试的小atom db,其中包含一个可以存储状态的函数。您可以稍后在最终使用的任何db上抽象此函数
(defdb(atom{}))
(记忆中的defn![得分db卡]
(交换!分数数据库更新(:id卡)#(如果%(inc%)0)))
现在我们可以测试它了
##_user=>(>>卡数据西班牙语动词优先(记住!db))
{“c1”0}
#_用户=>(>>卡数据秒(记住!db))
{“c1”0,“c2”0}
#_用户=>(>>卡数据优先(记住!db))
{“c1”1,“c2”0}
这很有效。但我们可以进一步将过滤抽象为一个selecttags
函数
(定义选择标签[卡和标签]
(过滤(>%:标签(每?(>>标签展平(移除零?))卡))
(德文西班牙语[卡片和标签]
(选择标签卡“西班牙语”标签)
(定义动词[卡片和标签]
(选择标签卡“动词”标签)
#_用户=>(西班牙语(卡片数据))
({:id“c1”、:front“corler”、:back“To run”、:tags#{“动词”“西班牙语”}{:id“c2”、:front“queryr”、:back“To want”、:tags#{“动词”“西班牙语”}})
#_用户=>(动词(西班牙语卡数据))
({:id“c1”、:front“corler”、:back“To run”、:tags#{“动词”“西班牙语”}{:id“c2”、:front“queryr”、:back“To want”、:tags#{“动词”“西班牙语”}})
现在我们可以把它们组合起来了
(定义西班牙语动词[卡片和标签]
((复合西班牙语动词)卡片标签)
;; 或(应用西班牙语卡片“动词”标记)
;; 甚至(应用选择标记卡“动词”“西班牙语”标记)
#_用户=>(>>卡数据优先(记住!db))
{“c1”2,“c2”0}
如果您熟悉SQL,应该立即开始使用Walkable SQL库和sqlite:
您将从SQL的规范化中受益匪浅。Walkable将使以树结构获取数据变得轻而易举,只需按几个键即可进行过滤。不要浪费时间与atom打交道,这个领域并不复杂,不值得花时间制作CRUD原型。你将使用什么样的UI?命令行,SPA web,普通web。。。?