17

最近のいくつかの質問から離れて、私は古いボギーマンにスポットライトを当てることにしましたOverlappingInstances.

数年前、私は真剣にこの質問をしていたかもしれません: 結局のところ、あなたは便利なデフォルト インスタンスを提供でき、他の人は必要に応じてより具体的なインスタンスでオーバーライドすることができます。

途中で、私は、OverlappingInstances実際にはそれほどきれいではなく、避けるのが最善である視点に対していくらかの感謝を吸収しました。主に、他の大きな拡張機能とは異なり、理論的に十分な根拠がないという事実に起因しています。

でも考えてみると、何が本当に悪いのか、他の人に聞かれたら説明できるかどうかわかりません。

私が探しているのは、OverlappingInstancesそれが型システムや他の不変条件を破壊することによるものであろうと、単に一般的な予期せぬことや乱雑であろうと、使用が悪いことを引き起こす可能性がある方法の具体的な例です。

私が知っている特定の問題の1つは、単一のモジュールインポートを追加または削除するだけではプログラムの意味を変更できないというプロパティが壊れることです。拡張機能をオンにすると、新しいインスタンスの重複が静かに追加または削除される可能性があるためです。なぜそれが不愉快なのかはわかりますが、なぜそれが驚くほどひどいのかわかりません.

おまけの質問: 有用ではあるが、理論的に根拠のない、悪い出来事につながる可能性のある拡張機能について話している限り、どうしてGeneralizedNewtypeDeriving同じ悪い評判がつかないのでしょうか? 否定的な可能性がよりローカライズしやすいからでしょうか。何が問題を引き起こすのかを見て、「それをしないでください」と言う方が簡単だと思いますか?

(注:答えの矢面に焦点を当てた方がいいと思います。説明が少なくて済むのではありOverlappingInstancesません。)IncoherentInstances

編集:ここにも同様の質問に対する適切な回答があります。

4

1 に答える 1

19

haskell言語が従おうとする1つの原則は、特定のモジュールにメソッド/クラスまたはインスタンスを追加することで、特定のモジュールに依存する他のモジュールがコンパイルに失敗したり、異なる動作をしたりすることはありません(依存モジュールが存在する限り)明示的なインポートリストを使用します)。

残念ながら、これはOverlappingInstancesで壊れています。例えば:

モジュールA:

{-# LANGUAGE FlexibleInstances, OverlappingInstances, MultiParamTypeClasses, FunctionalDependencies #-}

module A (Test(..)) where

class Test a b c | a b -> c where
   test :: a -> b -> c

instance Test String a String where
    test str _ = str

モジュールB:

module B where
import A (Test(test))

someFunc :: String -> Int -> String
someFunc = test

shouldEqualHello = someFunc "hello" 4

shouldEqualHelloモジュールBの「hello」と同じです。

次に、Aに次のインスタンス宣言を追加します。

instance Test String Int String where
    test s i = concat $ replicate i s

これがモジュールBに影響を与えない場合は、望ましいでしょう。これは、この追加の前に機能し、後で機能するはずです。残念ながら、そうではありません。

モジュールBは引き続きコンパイルされますが、現在shouldEqualHelloはに等しくなってい"hellohellohellohello"ます。元々使用していたメソッドが変更されていないにもかかわらず、動作が変更されました。

さらに悪いことに、モジュールからインスタンスをインポートしないことを選択できないため、古い動作に戻る方法がありません。ご想像のとおり、これは下位互換性にとって非常に悪いことです。重複するインスタンスを使用するクラスに新しいインスタンスを安全に追加できないため、モジュールを使用するコードの動作が変わる可能性があります(特にライブラリコードを記述している場合はそうです)。変更を追跡するのは非常に難しいため、これはコンパイルエラーよりも悪いです。

私の意見では、重複するインスタンスを使用する唯一の安全な時期は、追加のインスタンスが必要ないことがわかっているクラスを作成しているときです。これは、トリッキーなタイプベースのコードを実行している場合に発生する可能性があります。

于 2012-06-08T04:13:58.560 に答える