マット・テンダーで書かれたarticleを読んでいるうちに、私は次のような見解を見ました。Haskell型システムに正しさの制約を直接エンコードするか?
経験のあるプログラマはHaskellの型システムに直接
を正し制約をコードに熟達誰かがこの文の意味を説明したり、簡単な例を提供することはできますか?
マット・テンダーで書かれたarticleを読んでいるうちに、私は次のような見解を見ました。Haskell型システムに正しさの制約を直接エンコードするか?
経験のあるプログラマはHaskellの型システムに直接
を正し制約をコードに熟達誰かがこの文の意味を説明したり、簡単な例を提供することはできますか?
これは、本当にさまざまな異なるテクニックをカバーすることができます。最も単純なのは基本的に避けられないことです:可変状態またはユーザー入力に依存する可能性のある値をnullにするには、型システムでそれをマークする必要があります。これはそれぞれMaybe
,ST
、IO
となります。したがって、上記の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 levelでPeano 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詳細を参照してください。
私の意見では、見たことがあるような展覧会ではしばしば伝えられないことの1つは、このタイプの正確さは、「自然に」起こらないものであることです。他の言語に由来するプログラマーには明らかではないタイプを設計する技術を使用することに由来します。私の好きな例の1つはthe Haskell Wiki page on phantom typesです。
data FormData a = FormData String
やっa
を何:あなたは、そのページ上のセクション1を見れば、彼らは(IMO代わりdata
のnewtype
宣言する必要があります)この例がありますか?さて、それは人工的に、人工的に "本当に"同じであるにもかかわらず、FormData "foo" :: FormData Unvalidated
とFormData "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
は、今、私たちは、タグに敏感であることを
Hypercube
と
get
を定式。私は実際にこの改正された例でそれをより具体的にするつもりです。私たちは、これを起動します。
{-# 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
を作成しないようにすると、発信者はHypercube
にCell
の値を持たないと尋ねることはできません。
クレジット:I learned this technique by asking here in Stack Overflow。