2012-02-02 7 views
7

これは哲学的な質問ですが、私は公式の文書や「神の言葉」(読者:SPJ)によって答えたいと思っています。ハスケル委員会が、パターンマッチングに基づいたより統一的な解決策ではなく、明示的なインタフェースを型式で要求することを選択したという特別な理由はありますか?パターンマッチングだけでなく、なぜタイプキャスティングを使用するのですか?

例として

Eqを取る:

class Eq a where 
    (==), (/=) :: a -> a -> Bool 
    x == y = not $ x /= y 
    x /= y = not $ x == y 

instance Eq Int where 
    (==) = internalIntEq 

を私たちは、代わりにこのような何かを行うことができなかったのはなぜ(疑似ハスケルとクマ):Haskellはした場合、ある

(==), (/=) :: a -> a -> Bool 
default x == y = not $ x /= y    -- 1 
default x /= y = not $ x == y 

(Int a) == (Int b) = a `internalIntEq` b -- 2 

通常のデータ型のパターンマッチングを可能にする:

  • プログラマーが作成できるアドホックのクラス、すなわち、instanceは暗黙のだろう(2)

  • タイプまだ推測されると、静的マッチした可能性があり(SupportsEqualsEquals a => ...

  • デフォルトの実装は、「無料で」

  • クラスの来る可能性

デフォルトのパターン(1)を指定する方法が必要になりますが、それ以前に宣言されていますがs、常に最後に一致します。これらの仮想的な特徴のいずれかがハスケルに固有のものと衝突するか?タイプを正確に推論することが困難または不可能になるか?それは、Haskellの残りの部分と非常にうまく連携する強力な機能のように思われるので、We Do It Do It Way™という理由があると思います。アドホック多型のこのメカニズムは単に ad-hocですか?

+0

私はこのに精通していないんだけど、私は一つの大きな問題は、あなたがparametricityを失うということだと思うので、無料の定理:あなたはどのような 'ID ::知っている - (> A'または' FST ::、 b) - > a'は型のシグネチャだけで行います。なぜならそれらはパラメトリック多形性しか持たないからです。何らかのタイプチェイスの仕組みがあれば、パラメトリック性が失われます。たとえば、 'a - > a - > Bool'は、Haskell(' const $ const True'と 'const $ const False')で2つの(合計)実装しか許されません。 typecaseがある場合、この保証は失われます。 –

+0

@ AntalS-Z:私はあなたを正しく理解していることを確認しています。 'id :: a - > a'を宣言し、' id(Int i)= i + 1'を定義できると言っていますか?これはそうではないので、後者の定義は 'SupportsPlus a => a - > a'のタイプになります。これは互換性がありません。 –

+5

それはあなたの質問から聞こえるようなものです。 '(==)'の型署名は 'a - > a - > Bool'として与えられます。 「タイプクラス」「SupportsEquals」を指定する必要がある場合は、あなたが行ったすべての構文が周囲の構文と交換されているように見えます。なぜそれが*別のものかはわかりません。そして、私はマルチパラメータ型のクラス、関数の依存関係、または関連する型を表現することはできないと考えていますが、これらは当然のことではありませんでした。実際、より高級なタイプのクラスを表現することはできますか? 'return :: a m a'は' a'ではなく 'm'の上でアドホックになるはずです。 –

答えて

12

アドホック多型のこのメカニズムは、あまりにもアドホックなのでしょうか?

この質問は、Philip WadlerとSteve Blottの1988年の論文How to make ad-hoc polymorphism less ad-hocにリンクされています。そこで、彼らはTypeクラスのアイデアを提示します。ワドラーは、おそらくこの「神の言葉」です。

提案された「Haskellデータ型のパターンマッチング」手法にはいくつか問題があります。

パターンマッチング技術は、mempty :: Monoid a => aなどの多型定数を定義するには不十分です。です。

パターンマッチングのテクニックは、より悪い方法を除いて、まだタイプクラスに戻っています。タイプクラスをタイプ(タイプ)に分類してください。しかし、パターンマッチング技術はそれをむしろ曖昧にします。 foobarの機能が「同じ」クラスの一部であることをどのくらい正確に指定する必要がありますか? 使用する単一の多型関数ごとに新しい型を追加する必要がある場合、型の制約は完全に解読不能になります。

パターンマッチング技術は、言語仕様を複雑にするという新しい構文をHaskellに導入します。 defaultのキーワードはそれほど悪くはありませんが、 "タイプ上のパターンマッチング"は新しく混乱します。

「通常のデータ型」のパターンマッチングは、ポイントフリースタイルを破ります。 (==) = intEqの代わりに、(Int a) == (Int b) = intEq a bがあります。人工パターンのこの種の一致は、エタ削減を防ぐ

最後に、は、タイプシグネチャの理解を完全に変更します。a -> a -> Fooは現在保証であり、入力を検査することはできません。 2つの入力が同じタイプであることを除いて、a入力については何も仮定できません。[a] -> [a]は再びリストの要素があなたにTheorems for Free(別Wadlerの紙)を与える、いかなる意味のある方法でを検査することができないことを意味します。

は、これらの懸念に対処する方法があるかもしれませんが、私の全体的な印象は、そのタイプのクラスがすでにエレガントな方法でこの問題を解決し、技術をマッチング提案パターンはいくつかの問題を引き起こしている間、何のメリットが追加されていません。

+1

wrt。あなたの最後の点は、私は彼の提案が多形性を完全に変更することではないと考えています。私は、使用された各関数に対して型制約の束を追加するだけだと思います。すなわち 'a - > a - > Foo'は入力を検査することができないことを保証します。暗黙的な型クラスが使用されている場合、それは署名の一部になります。 – gatoatigrado

+0

洞察と論文にとても感謝しています。私はあなたのポイントのカップルに同意します。Typeclassの制約は、目に見える必要がないため、読むことができません。「(+)は(foo :: Foo + bar :: Bar)で定義されていません」と言うこともできます。型署名についてのポイントは重要です。 'id :: a - > a'はまだ残っているという事実を知っています。なぜなら、他の関数を含む定義には互換性のない署名があるからです。また、再。あなたはアプリケーション言語(連結言語とは対照的に)で書いているので、すべてがポイントフリーであるとは限りません。 –

+0

@gatoatigrado:はい、それはまさに私の言いたいことです。私たちがすでに持っている定理を破ることはありません。少なくとも私はそうは思わない。 –

4

私は神の言葉を知らないが、ここにいくつかの議論がある。

同じモジュール内でユニークな関数を定義することはもうありません。今すぐ書くことができます

(==) = internalIntEq 
(==) = internalFloatEq 

これはコードを読みにくくします。同様のことを行う "TypeBasedNameResolution"という提案がありますが、このようなタイプの分岐は、異なるモジュールの(==)に対してのみ行われます。

コンパイラに識別子を追加するのは悪い習慣です。あなたの場合、タイプクラスSupportsEqualsEqualsが自動的に作成されます。新しいユーザーは「どこから来たのか」と尋ねるかもしれません。それを定義するソースはありません。

インスタンス署名を書き込んでも、あなたが考えることはほとんどありません。あなたは必要なパラメータを得ることができます。 ghciの:t internalIntEq。私はそれがより便利かもしれないと思うが、私は "Eq==internalIntEqの場合のインスタンスの種類は何ですか?

さらに高度なクラスの機能は不明です。関連する型や関数の依存関係はどこに置いていますか?これらは私にとって本当に重要です!

デフォルト設定では、モジュラーコンパイルが難しくなります。あなたは自由に拡張可能なクラスを取得するつもりはありません。私は特定の種類a_0ための新しい/=インスタンスを提供する場合

f :: Supports[==] a => a -> a -> Bool 
f = (/=) 

私はそれを理解するように、これは、今

f :: Instance (Supports[==]) a -> a -> a -> Bool 
f eq_inst x y = not (x eq_inst.== y) 

にダウンコンパイルし、考えてみて、その後、 f

をいくつか x :: a_0を養います
f x x = not (x == x) 
-- computation you really want: f x x = x /= x, using the new /= instance for a_0 

あなたは「いつ愚かなことになるのですか?fをに限定してくださいの代わりにSupports[/=]? "しかし、文脈は機能以上の署名から来ることができます。高次関数などから来ることができます。

希望します。

関連する問題