2

对于工作,我想以最简洁的方式描述标准医学公式(用于报告药物副作用)的格式。(粗略地说,通过打嗝来渲染它,但不仅如此,这就是为什么我不直接把它写成打嗝结构)

例如,部分描述将是:

{"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 的新手,所以几乎所有的设计建议都是受欢迎的;))

谢谢!

4

2 回答 2

1

你是对的,宏不能告诉eval将其结果拼接到外部表达式中。一种直接的解决方法是将整个映射定义包装在一个宏中,该宏识别prefix表达式并将它们转换为结果映射定义中的适当键值序列。

您也可以仅通过将子图与以下内容粘合来使用函数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})

这可能更冗长但也可能更具可读性。

编辑:还有一个限制:在评估任何宏(内部或外部)之前创建映射文字。一个参数是映射字面量的宏将得到一个映射,而不是某种形式,其评估最终会产生映射。当然,这个映射中的键和值是未评估的形式,但映射本身是一个正确的映射 ( IPersistentMap)。

特别是这意味着文字需要包含偶数个形式,所以:

 (my-smart-macro { (prefix "reporter" ...) } )

将失败之前my-smart-macro有机会扩大prefix。另一方面,这将成功:

(another-macro { (/ 1 0) (/ 1 0) })

...提供宏从其输入映射中过滤掉无效的算术表达式。

这意味着您可能不想将映射文字传递给宏。

于 2012-08-09T15:49:23.347 回答
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* "reportertitle")访问它并(assoc *data* "reportertitle" *new-title*)制作它的新版本之类的事情,不如使用(get-in *data* [:reporter :title])and (assoc-in *data* [:reporter :title])

外观上的变化是将这些基于字符串的键转换为 Clojure 关键字。我建议这样做的主要原因是它会更惯用,并且阅读您的代码可能会更清晰。有关为什么要使用关键字的更好讨论,请参见此处此处

现在,我意识到我所说的一切都预先假定您实际上可以更改数据的结构以及关键字的命名方式。您说“这些键是标准名称,我无法更改它们”,这似乎表明这种类型的解决方案不适合您。但是,也许您可​​以在两种形式之间进行相互转换。如果您从某个地方导入此数据并且它已经具有您在上面给出的格式,您可以将其转换为带有关键字的嵌套映射形式,并在您对它进行任何操作时保持这种状态。然后,当您导出要实际输出或使用的数据(或它所服务的任何最终目的)时,您会将其转换回上面的形式。

我应该说,我个人完全不喜欢这种“相互转换”的想法。我认为它区分了“代码”和“数据”的概念,考虑到这样做只是为了让代码“看起来和感觉更好”而不是数据,这似乎是一种耻辱。话虽如此,我建议它以防你听起来不错

于 2012-08-11T01:03:32.413 回答