Clojure 将一个集合拼接到另一个集合中
对于工作,我想以最简洁的方式描述标准医疗处方(用于报告药物副作用)的格式。(粗略地说,是通过hiccup进行后期渲染,但不仅如此,这就是为什么我不直接将其作为hiccup结构编写的原因) 例如,部分描述将是:Clojure 将一个集合拼接到另一个集合中,clojure,Clojure,对于工作,我想以最简洁的方式描述标准医疗处方(用于报告药物副作用)的格式。(粗略地说,是通过hiccup进行后期渲染,但不仅如此,这就是为什么我不直接将其作为hiccup结构编写的原因) 例如,部分描述将是: {"reportertitle" [:one-of "Dr" "Pr" "Mrs" "Mr"] ; the reporter is usually the physician "reportergivenname" :text "reporterfamilyname" :text
{"reportertitle" [:one-of "Dr" "Pr" "Mrs" "Mr"] ; the reporter is usually the physician
"reportergivenname" :text
"reporterfamilyname" :text
"reporterorganization" :text
"reporterdepartment" :text
....
"literaturereference" :text
"studyname" :text
....}
这些键是标准名称,我无法更改它们,但我希望能够轻松地对其进行分解:例如,前缀“reporter”在整个地图中都被广泛使用,我希望能够对其进行分解,例如:
{ (prefix "reporter"
"title" [:one-of "Dr" "Pr" "Mrs" "Mr"]
"givenname" :text
"familyname" :text
"organization" :text
"department" :text)
.....
"literaturereference" :text
"studyname" :text
....}
但这是行不通的,因为我认为我无法在外部映射中“集成”(拼接,我相信是正确的术语)前缀的结果,无论是函数还是宏
在保持高水平的声明性/简洁性的同时,是否有解决方案来实现这一点?(整个表单非常庞大,可能会被非开发人员阅读)
(因为我是Clojure的新手,几乎所有的设计建议都是受欢迎的;)
谢谢 您是对的,宏不能告诉
eval
将其结果拼接到外部表达式中。一种简单的方法是将整个地图定义包装在一个宏中,该宏可以识别前缀
表达式,并将它们转换为结果地图定义中的适当键值序列
您也可以仅通过使用merge
粘合子贴图来使用函数执行此操作:
(defn pref-keys [p m] (apply hash-map (apply concat (for [[k v] m] [(str p k) v])))))
(merge
(pref-keys "reporter"
{"title" [...]
"givenname" :text
...})
{"literaturereference" :text
"studyname" :text})
这可能有点冗长,但也可能有点可读性
编辑:还有一个限制:在计算任何宏(内部宏或外部宏)之前创建映射文本。参数为map literal的宏将获得map,而不是其求值最终生成map的某种形式。当然,此映射中的键和值是未计算的形式,但映射本身是一个正确的映射(IPersistentMap
)
特别是,这意味着文本需要包含偶数形式,因此:
(my-smart-macro { (prefix "reporter" ...) } )
在我的智能宏
有机会展开前缀
之前将失败。另一方面,这将取得成功:
(another-macro { (/ 1 0) (/ 1 0) })
。。。假设宏从其输入映射中过滤出无效的算术表达式
这意味着您可能不想将映射文字传递给宏。事先,我应该说这个答案可能根本不是您想要的。这将是一种完全改变您的数据结构的方式,您可能会说这不是您可以做的事情。无论如何,我之所以建议这样做,是因为我认为这将是对您的数据结构的一个很好的改变 因此,我建议您重新设想您的数据:
{:reporter {:title "Dr, Pr, Mrs, or Mr here"
:given-name "text here"
:family-name "text here"
:organization "text here"
:department "text here"
...}
:literature-reference "text here"
:study-name "text here"
...}
我在这里提出了两个变化:一个是结构性的,另一个是“装饰性的”。结构上的一个是在那里嵌套另一张地图,用于与记者相关的东西。我个人认为这使数据更加清晰,而且也同样容易获取。与其做类似于(get*data*“reportertite”)
的操作来访问它,或者(assoc*data*“reportertite”*新标题*)
来制作新版本,不如(get in*data*[:reporter:title])
和(assoc in*data*[:reporter:title])
表面上的变化是将这些基于字符串的键转换为Clojure关键字。我建议这样做的主要原因是,这样会更加惯用,而且阅读代码可能会更加清晰。有关为什么使用关键字的更好讨论,请参阅maybe或
现在,我意识到我所说的一切都假设您实际上可以更改数据的结构和关键字的命名方式。您说过“密钥是标准名称,我不能更改它们”,这似乎表明这种类型的解决方案不适合您。然而,也许你可以在这两种形式之间相互转换。如果您从某个地方导入此数据,并且它已经具有上面给定的格式,则可以将其转换为带有关键字表单的嵌套映射,并在使用它时保持这种方式。然后,当您导出要实际输出或使用的数据(或它所服务的任何最终目的)时,您会将其转换回上面的表单
我应该说,我个人一点也不喜欢这种“相互转换”的想法。我认为它将“代码”和“数据”的概念区分开来,考虑到只有让代码比数据“看起来和感觉更好”才行,这似乎是一种耻辱。话虽如此,我还是建议这样做,以防听起来不错。是的,我想我得把我的宏称为更上游的宏。我可以在编译时使用clojure.zip函数来查找和更改“prefix”表单吗?还是有更方便的方法?现在您已经谈到了,替换嵌套在宏参数中的术语似乎非常常见(我相信我在Scheme中看到过类似的内容)。我建议将
(前缀“reporter”bla bla bla)
替换为[“reporter”bla bla bla]
。这样你就不需要写宏了(你可以写普通函数)。@NikitaBeloglazov:我根据你的建议对非宏版本进行了编辑。我同意你的解决方案会更“clojurian”。我到目前为止所做的工作在这里是可用的:请注意,我切换到向量是因为:{}(默认情况下?)不处理排序(我希望能够指定字段的显示顺序),并且“文本”应该是默认字段格式(即键不总是有值)。最后,我希望能够指定与显示相关的“操作”(例如:section指示应该创建一个div,但我不只是放“div”,因为正如我所说,我不只是用该数据生成HTML)。