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

しかし、関数であろうとマクロであろうと、外側のマップ内で「プレフィックス」の結果を「統合」(スプライス、正しい用語だと思います) できないと思うので、これは機能しません。

高レベルの宣言性/簡潔性を維持しながらこれを達成するための解決策はありますか? (フォーム全体が巨大で、非開発者が読む可能性があります)

(私は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})

これはもう少し冗長かもしれませんが、おそらくもう少し読みやすいでしょう。

編集:もう1つの制限があります。マップリテラルは、マクロ(内部または外部)が評価される前に作成されます。引数がマップ リテラルであるマクロは、評価によって最終的にマップが生成される形式ではなく、マップを取得します。もちろん、このマップのキーと値は未評価の形式ですが、マップ自体は適切なマップです ( 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"
 ...}

私がここで提示している変更は 2 つあります。1 つは構造的なもので、もう 1 つは「表面的な」ものです。構造的なものは、レポーター関連のもののためにそこに別のマップをネストすることです. 個人的には、これによりデータがより明確になり、アクセスしやすくなると思います. それに(get *data* "reportertitle")アクセスし(assoc *data* "reportertitle" *new-title*)て新しいバージョンを作成するようなことをする代わりに(get-in *data* [:reporter :title])(assoc-in *data* [:reporter :title]).

表面的な変更は、これらの文字列ベースのキーを Clojure キーワードに変換することです。これを提案する主な理由は、それがより慣用的であり、コードを読みやすくする可能性があるためです。キーワードを使用する理由についてのより良い議論については、おそらくここまたはここを参照してください。

さて、私が言ったことはすべて、データの構造とキーワードの命名方法を実際に変更できることを前提としていることに気づきました。「キーは標準名なので変更できません」とおっしゃいましたが、これは、このタイプのソリューションがうまくいかないことを示しているようです。ただし、2 つの形式間で相互変換できる可能性があります。このデータをどこかからインポートしていて、すでに上記の形式になっている場合は、それをキーワード付きのネストされたマップ形式に変換し、それを使用して何をしてもその状態を維持します。次に、実際に出力または使用するためにデータをエクスポートするとき (またはそれが提供する最終的な目的は何であれ)、上記の形式に変換します。

個人的には、この「相互変換」のアイデアはまったく好きではありません。「コード」と「データ」の概念を分けていると思いますが、データよりもコードを「見栄えがよく」するためだけに行われることを考えると、これは非常に残念なことです。そうは言っても、あなたに良さそうに思えば、私はそれを提案しています

于 2012-08-11T01:03:32.413 に答える