2012-02-11 1 views
6

Javaの背景から、静的型の安全性が非常に高く、クロージャープログラマがデータ型定義の問題をどのように扱うのか不思議です。clojureでのデータフォーマットの安全性

これは既存の質問「Clojureの型安全性」に似ていますが、コンパイル時に型をチェックする方法の面に重点を置いています。問題は実用的に対処されている。

具体的な例として、特定のドキュメント形式を扱うエディタアプリケーションを検討しています。各ドキュメントは、いくつかの異なる種類(グラフィックス要素、フォント要素など)で提供される要素で構成されています。さまざまな要素タイプのエディタがあります。また、ドキュメントをネイティブオンデマンド形式のバイトストリームから/ディスクフォーマット。

私が興味を持っている基本的な問題は、エディタと読み書きの機能が共通のデータ形式に同意しなければならないということです。 Javaでは、文書のデータをオブジェクトグラフとしてモデル化します。 1つのクラスは文書を表し、1つのクラスは各要素の種類を表します。このようにして、データの構造がどのようなものかをコンパイル時に保証し、グラフィックス要素のフィールド「幅」は整数であり、浮動小数点ではないことを保証します。幅が正であることを保証するものではありませんが、ゲッター/セッターインターフェースを使用すると、対応するクラスに不変の保証が追加されます。

これに頼ることで、このデータを扱うコードがより簡単になり、コンパイル時または実行時にフォーマット違反がキャッチされる可能性があります(一部のコードでは不変量に違反するデータを変更しようとします)。

Clojureで同様の「データ形式の信頼性」を達成するにはどうすればよいですか?私が知る限り、コンパイル時のチェックを実行する方法はなく、関数のインターフェイスの背後にあるドメインデータを隠すことは、非慣用的なもの(または私が誤解しているかもしれません)として推奨されていないようです。Clojureの開発者は、それらの機能に渡されるデータの形式?できるだけ早くエラーになるようにするにはどうすればいいですか?ユーザが20分以上編集してディスクに保存しようとした後ではありません。保存機能はフォントのリストにグラフィック要素がエディタのバグ?

私はClojureと学習に興味がありますが、まだ実際のソフトウェアは書いていないので、私はちょうど混乱している可能性があります。その答えは非常に単純です - もしそうなら、あなたの時間 :)。

答えて

8

以下のように、データを構成して操作するための検証APIを使用することに関して、間違っているか独立しているものはありません。また

(defn text-box [text height width] 
    {:pre [(string? text) (integer? height) (integer? width)]} 
    {:type 'text-box :text text :height height :width width}) 

(defn colorize [thing color] 
    {:pre [(valid-color? color)]} 
    (assoc thing :color color)) 

... (colorize (text-box "Hi!" 20 30) :green) ... 

、参照(VARS、参考文献、原子剤)は常に有効な状態を確保するために使用することができる関連validator functionを有することができます。

+0

これまでの回答に感謝します。これはむしろ自由な質問ですので、私はもう一度受け入れる前に待っています。バリデータ関数は興味深い解決策のように聞こえるが、あなたの状態として大きな文書を持っている場合は(例にとどまって)、小さな変更が行われるたびに完全に検証することは非効率であるように思える。そのようなモデルでは、操作機能が好ましい。 – Medo42

5

良い質問 - 静的型付き言語から動的型型に移動するには、型の安全性についてもう少し注意が必要です。幸いにも、TDD技術はここで膨大な量を助けます。

私は、通常、データ構造に関するすべての前提をチェックする「検証」機能を書いています。私は不変の仮定のためにJavaでこれをしばしば行いますが、Clojureでは型のような考え方もチェックする必要があるため、より重要です。

あなたはその後、いくつかの方法で検証機能を使用することができます。

  • をREPLで簡単にチェックとして:ユニットテストで(validate foo)
  • (is (validate (new-foo-from-template a b c)))
  • キー機能の実行時チェックとして、例えば(read-foo some-foo-input-stream)は、あなたが複数の異なるコンポーネントタイプの木である複雑なデータ構造を持っている場合は、各コンポーネントタイプのvalidate関数を記述し、ため文書全体のコール検証のための検証機能を持たせることができる有効な

であることを確認各サブコンポーネントは再帰的にプロトコルまたはマルチメソッドのいずれかを使用して、各コンポーネントタイプに対してvalidate関数を多態性にするのが良いトリックです。