2013-04-25 1 views

答えて

18

これは、本当にさまざまな異なるテクニックをカバーすることができます。最も単純なのは基本的に避けられないことです:可変状態またはユーザー入力に依存する可能性のある値をnullにするには、型システムでそれをマークする必要があります。これはそれぞれMaybe,STIOとなります。したがって、上記の3つのタイプのいずれかにないものがある場合は、それをnullにすることはできません。

上記の手法は、言語にとって非常に基本的なものであり、基本的に避けられないものです。しかし、もう少し面白いセキュリティと正しさを向上させるために型システムを使用する他の方法があります。

SQLインジェクションを防止する便利な例が1つあります。 SQLインジェクションは、Webアプリケーションの共通の問題です。基本的な考え方は、this XKCD cartoonを参照してください。実際に型システムを使用して、データベースに渡された文字列が確実に墨塗りされていることを確認できます。ユーザーの戻りRaw値の代わりに、通常の文字列からの入力を取得するために必ず、すべての機能を作ること、そして、

newtype Raw a = Raw a 

:基本的な考え方は、「生」の文字列のための新しいタイプを作成することです。最後に、あなただけのサニタイズ機能を必要とする:通常の機能がStringではなくRawを受け入れる

sanitize :: Raw String -> String 

ので、誤っunsanitized文字列を渡すことができません。 newtypeを使用してRawを定義したため、ランタイムオーバーヘッドはまったくありません。

Yesodは、主なHaskell Webフレームワークの1つで、SQL注入を防ぐためにこのような手法を使用しています。また、型システムを使用してデータベース内のリンクが壊れないようにするなど、いくつかのクールな方法があります。あなたはそれをチェックアウトする必要があります。

実際に極端な場合、タイプシステムを使用してマトリックスのサイズが正しいことを確認することもできます。これを行うには非常に簡単な方法があります。まず、我々はタイプレベルの番号が必要になります。

data Z 
data S n 

(ここではtype levelPeano Arithmeticを使用している。)アイデアは単純です:Zは0とSであることは後継機能であるので、S Zは1で、S (S Z)です2など。

現在、安全な行列乗算関数を記述することができます

matMul :: Mat a b -> Mat b c -> Mat a c 

この機能は、内寸法が一致し、そして得られた行列は、そのタイプの右の寸法を有することを保証場合は、行列を乗算させます。

Type-safe matrix multiplication詳細を参照してください。

7

私の意見では、見たことがあるような展覧会ではしばしば伝えられないことの1つは、このタイプの正確さは、「自然に」起こらないものであることです。他の言語に由来するプログラマーには明らかではないタイプを設計する技術を使用することに由来します。私の好きな例の1つはthe Haskell Wiki page on phantom typesです。

data FormData a = FormData String 

やっaを何:あなたは、そのページ上のセクション1を見れば、彼らは(IMO代わりdatanewtype宣言する必要があります)この例がありますか?さて、それは人工的に、人工的に "本当に"同じであるにもかかわらず、FormData "foo" :: FormData UnvalidatedFormData "foo" :: FormData Unvalidatedが互換性のない型を持つようになり、コードを強制的に混ぜ合わせないようにすることができます。さて、ページが言っていることを繰り返さないようにしましょう。比較的簡単に読むことができます(少なくともセクション1)。

私のオンオフプロジェクトで使用しているさらに複雑な例:OLAPハイパーキューブは、整数インデックスではなく、人や人のようなデータモデルオブジェクトによってインデックス付けされた一種の配列と見ることができます。日、製品ラインなど:

-- | The type of Hypercubes. 
data Hypercube point value = ... 

-- | Access a data point in a hypercube. 
get :: Eq point => Hypercube point value -> point -> value 

-- | This is totally pseudocode... 
data Salesperson = Mary | Joe | Irma deriving Eq 
data Month = January | February | ... | December deriving Eq 
data ProductLine = Widget | Gagdet | Thingamabob 

-- Pseudo-example: compute sales numbers grouped by Salesperson, Month and 
-- ProductLine for the combinations specified as the "frame" 
salesResult :: HyperCube (Salesperson, Month, ProductLine) Dollars 
salesResult = execute salesQuery frame 
    where frame = [Joe, Mary] `by` [March, April] `by` [Widgets, Gadgets] 
      salesQuery = ... 

-- Read from salesResult how much Mary sold in Widgets on April. 
example :: Dollars 
example = get salesResult (Mary, April, Widgets) 

私は恐れるよりも理にかなってほしいと思います。とにかく、ポイントの例は次のような問題である:

badExample :: Dollar 
badExample = get salesResult (Irma, January, Thingamabob) 

一つの可能​​:getの種類、ここではレイアウトとして、あなたはそれを持っていないあなたにポイントの価値を伝えるためにHypercubeを依頼することができますこれに対する解決策は、getの操作をvalueの代わりにMaybe valueに戻すことです。しかし、実際にはもっとうまくいくことができます。 Hypercubeに含まれている値についてのみ尋ねることができるAPIを設計することができます。キーはFormDataの例と似ていますが、より洗練されたものです。まず、このファントムタイプをご紹介:

data Cell tag point = Cell { getPoint :: point } deriving Eq 

は、今、私たちは、タグに敏感であることを Hypercubegetを定式。私は実際にこの改正された例でそれをより具体的にするつもりです。私たちは、これを起動します。

{-# LANGUAGE ExistentialTypes #-} 

data AuxCube tag point value = 
    AuxCube { getFrame :: [Cell tag point] 
      , get :: Cell tag point -> value } 

-- This is using a type system extension called ExistentialTypes: 
data Hypercube point value = forall tag. Hypercube (AuxCube tag point value) 

-- How to use one of these cubes. Suppose we have: 
salesResult :: Hypercube (Salesperson, Month, ProductLine) Dollars 
salesResult = execute salesQuery points 
    where points = [Joe, Mary] `by` [March, April] `by` [Widgets, Gadgets] 
      salesQuery = ... 

-- Now to read values, we have to do something like this: 
example = case salesResult of 
       Hypercube (AuxCube frame getter) -> getter (head frame) 

私はExistentialTypesの使用がここであなたを混乱させる場合謝罪、しかし長い話を短くするために、どのようなことが、この例ではないことは、各Hypercubeはユニークな匿名のタグが付けられたAuxCube含まれていることを基本的に今度は2つの同じタイプのCellを持つことはできません。このため、モジュールシステムを使用して発信者がCellを作成しないようにすると、発信者はHypercubeCellの値を持たないと尋ねることはできません。

クレジット:I learned this technique by asking here in Stack Overflow

関連する問題