2011-10-07 20 views
9

こんにちは。私のclojureアプリケーションは、データAPIの欠如のために非常に急速に構造的に結合していることがわかりました.-名前が誤っている場合、例外がスローされるか、エラーが発生します。またリストの構造を間違えると間違いを起こしやすいことに気が付きました。(たとえば、リストの間違った部分を解体するなど).....clojureで堅牢なデータAPIを構築する方法

通常、私は自分のIDEを使って最小の順序付けされていないデータオブジェクトからの "正しい"データですが、これとは逆のパラダイムと思われます。

タイプシステムやIDEコードの補完がないと、クロージャーはどのようにしてコードを守りますか?

答えて

5

"スキーマ"(キーだけでなく値のタイプなど)にバリデータ関数を書き込むと、コード内の前後の条件の中でthmを使用します。構文はほとんど知られていないので、ここでは簡単に再読み込みします:

(defn foo [x y] ; works with fn too 
    {:pre [(number? x) (number? y)] 
    :post [(number? %) (pos? %)]} 
    (+ (* x x) (* y y))) 

これらはassertに依存しており、無効にすることができます。詳細については(doc assert)をご覧ください。

+0

これが掲載されて以来、core.typedがリリースされ、同じことをhttp://typedclojure.org/でも行うことができます – Ben

5

多分あなたはレコードを探していますか?

(require '[clojure.set :as cset]) 

(defrecord Person [name age address phone email]) 

    ;; Make a keyword-based constructor to verify 
    ;; args and decouple ordering. 
(let [valid #{:name :age :address :phone :email}] 
    (defn mk-person[& args] 
    (let [h (apply hash-map args) 
      invalid (cset/difference (set (keys h)) valid)]  
     (when-not (empty? invalid) 
     (throw (IllegalArgumentException. (pr-str invalid)))) 
     ; any other argument validation you want here 
     (Person. 
     (:name h) (:age h) (:address h) (:phone h) (:email h))))) 

=> (def p (mk-person :name "John" :email "[email protected]")) 
#:user.Person{:name "John", :age nil, :address nil, :phone nil, 
       :email "[email protected]"} 

今あなたが機能(例外)やキーワード(ない例外)を使用してデータにアクセスすることにより、入力ミスの名前の例外をしたいかどうかを選択することができます。

=> (.fax p) 
java.lang.IllegalArgumentException: 
    No matching field found: fax for class user.Person 
=> (:fax p) 
nil 

このアプローチでは、既存のメソッドと競合するフィールド名を避ける必要があります。 (@Jouniからのコメントを参照してください。)また

、あなたは検索用キーワードや無効なキーをチェックアクセサ関数で使用して、フィールド名の制限を回避することができます


(defn get-value [k rec] 
    (let [v (k rec ::not-found)] 
    (if (= v ::not-found) 
     (throw (IllegalArgumentException. (pr-str k))) 
    v))) 

=> (get-value :name p) 
"John" 
=> (get-value :fax p) 
IllegalArgumentException: :fax 
を「間違っている非構造リストの一部 "タイプの問題は、リスト内の"人 "のようなものをエンコードしようとしたことから来るかもしれません。 「郵便番号は「人」リストの3番目の「アドレス」リストの4番目の要素です」というようなことを覚えておく必要があります。

'classical' Lispでは、アクセサ関数を書くことで解決できるかもしれませんが、Clojureではレコードを使用するかもしれません。

Typosはどのプログラミング言語でも問題を引き起こします。できるだけ早くキャッ​​チしようとするとよいでしょう。

オートコンプリート機能を備えたJava IDEは、入力中にいくつかのタイプミスを犯す可能性があり、コンパイル時に静的型付けされた言語が多くのものをキャッチしますが、動的言語では実行時まで見つけられません。これは動的言語(Python、Rubyなど)の欠点だと考えている人もいますが、その人気から、​​プログラマーは、IDEの自動補完やコンパイル時のエラーの損失よりも、得られる柔軟性と保存されたコードが重要だと考えています。

どちらの場合も原則は同じです:原因を見つけるために必要なコードが少なくて済むため、以前の例外は優れています。理想的には、スタックトレースはあなたを誤植にまっすぐに導くだろう。 Clojureでは、レコードとアクセサ関数がそれを提供します。

+1

「サイズ」という名前のレコードフィールドはありません。 '(.size rec)'を呼び出すと、java.utilで定義された*メソッド* 'size'が呼び出されます。Clojureレコードが持つすべてのインタフェースのすべての無限メソッドについても同様です。 –

+0

@Jouniはい、使用できない17の名前があります。 'size'、' count'、 'values'、' meta'はおそらく最も面倒です。あなたはそれらを予約語として扱い、それらの使用を避けたり、独自のデータAPIを書く必要があります。私の知る限り。 –

関連する問題