2012-08-09 17 views
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 
....} 

的關鍵是標準名稱,我不能改變它們,但我希望能夠輕鬆分解事物:例如,在整個地圖中高度使用前綴「記者」,我希望能夠分解它,例如通過做:

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

但這不能工作,因爲我認爲我c註釋「集成」(拼接,我相信是正確的術語)在外部地圖內的'前綴'的結果,無論是函數還是宏。

有沒有解決方案來實現這一目標,同時保持高水平的聲明/簡潔? (整個窗體是巨大的,可能是由非開發人員可以讀取)

(由於我是新來的Clojure,幾乎每一個設計的建議是歡迎;))

謝謝!

回答

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

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

將失敗。另一方面,這將成功:

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

...提供宏從其輸入映射中篩選出無效的算術表達式。

這意味着您可能不想將地圖文字傳遞給宏。

+0

是的,我想我將不得不把我的宏叫上游。我可以在編譯時使用clojure.zip函數來查找和更改「前綴」表單嗎?還是有更方便的方法?現在你已經談論過了,看起來嵌入宏參數中的術語似乎很常見(我相信我在Scheme中看到過類似的東西)。 – 2012-08-09 15:56:05

+0

我建議用'[「記者」bla-bla-bla「'替換'(前綴」記者「bla-bla-bla」)。這樣你就不需要寫宏(你可以寫普通函數)。 – 2012-08-09 16:17:31

+0

@NikitaBeloglazov:我根據您對非宏版本的建議進行了編輯。 – 2012-08-09 18:19:13

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])

整體變化是將這些基於字符串的密鑰變成Clojure關鍵字。我提出這個建議的主要原因是,它會更習慣用法,並且可能會更清楚地閱讀您的代碼。有關爲什麼要使用關鍵字的更好的討論,請參閱herehere

現在,我意識到我所說的一切都假設您實際上可以可以更改數據的結構以及如何命名關鍵字。你說:「鑰匙是標準名稱,我無法改變它們」,這似乎表明這種類型的解決方案不適合你。 但是,也許你可以在兩種形式之間進行相互轉換。如果你從某個地方導入這些數據,並且它已經有了上面給出的格式,那麼你可以將它轉換爲嵌套地圖與關鍵字表單,並在你做任何事情時保持這種狀態。然後,當您將數據導出爲實際輸出或使用(或任何最終結果)時,您可以將它轉換回上面的形式。

我應該說,我個人根本不喜歡這種「相互轉換」的想法。我認爲它將「代碼」和「數據」的概念分開了,這看起來像是一種恥辱,認爲只有讓代碼「看起來和感覺比數據更好」。這就是說,我建議如果它聽起來不錯

+0

我同意你的解決方案會更「clojurian」。我到目前爲止所做的工作可以在這裏找到:http://goo.gl/9JK2R請注意,我切換到矢量因爲:{}(默認情況下?)不處理排序(並且我想能夠指定按照哪個順序字段應該出現)並且「文本」應該是默認的字段格式(即,鍵不總是具有值)。最後,我希望能夠指定與顯示相關的「操作」(例如:section指示應該創建一個div,但我不只是放「div」,因爲正如我所說的,我不僅用這些數據做HTML生成)。 – 2012-08-11 08:37:07