在另一个内部拼接一个集合

时间:2012-08-09 15:20:54

标签: clojure

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

例如,部分描述将是:

{"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
 ....}

键是标准名称,我无法更改它们,但我希望能够轻松分解事物:例如前缀“报告者”在整个地图中被高度使用,我希望能够将其分解,例如:做:

{ (prefix "reporter"
     "title" [:one-of "Dr" "Pr" "Mrs" "Mr"]
     "givenname" :text
     "familyname" :text
     "organization" :text
     "department" :text)
  .....
  "literaturereference" :text
  "studyname" :text
  ....}

但这不起作用,因为我认为我不能“整合”(拼接,我相信是正确的术语)“外部”的结果,无论是函数还是宏,都在外部地图内。

是否有解决方案来实现这一目标,同时保持高水平的声明/简洁性? (整个表格很大,可能会被非开发人员阅读)

(因为我是Clojure的新手,几乎所有的设计建议都是受欢迎的;)

谢谢!

2 个答案:

答案 0 :(得分: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) })

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

这意味着您可能不希望将地图文字传递给宏。

答案 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* "reportertitle")(assoc *data* "reportertitle" *new-title*),而不是像(get-in *data* [:reporter :title])那样访问它,而(assoc-in *data* [:reporter :title])创建新版本的文件,而不是{{1}}和{{1}}。

化妆品的变化是将这些基于字符串的键转换为Clojure关键字。我提出这个问题的主要原因是它更具惯用性,并且读取代码可能更清晰。有关使用关键字的原因的更好讨论,请参阅herehere

现在,我意识到我所说的一切预先假设您实际上可以改变数据的结构以及关键字的命名方式。你说“密钥是标准名称,我不能改变它们”,这似乎表明这种类型的解决方案对你不起作用。 然而,也许你可以在两种形式之间进行相互转换。如果您从某个地方导入这些数据,并且它已经具有您在上面提供的格式,您可以将其转换为嵌套地图与关键字形式,并在您对其执行任何操作时保持这种方式。然后,当您导出数据以实际输出或使用(或其服务的最终结束)时,您可以将其转换回上面的表格。

我应该说,我个人根本不喜欢这种“转换间”的想法。我认为它划分了“代码”和“数据”的概念,考虑到这样做只会使代码“外观和感觉更好”而不是数据,这似乎是一种耻辱。话虽这么说,我建议它,以防