2012-06-08 4 views
17

最近のいくつかの質問を元に戻して、私は古いボギーマンの灯台に、OverlappingInstancesを向けたいと思った。OverlappingInstancesについて何が悪いですか?

数年前、私は本質的にこの質問をしていたかもしれません:結局のところ、あなたは有用なデフォルトのインスタンスを提供することができます。

途中で私は、OverlappingInstancesが本当にとてもきれいでなく、避けられないという視点に感謝しました。主に他の大きな拡張とは異なり、理論的に十分に接地されていないという事実に由来しています。

しかし、それについて考えてみると、他の人に本当に悪いことを説明できるかどうかは分かりません。

私が探しているのは、OverlappingInstancesを使用すると、タイプシステムや他の不変条件を覆すことによるかどうか、あるいは一般的な予期せぬことや厄介さなど、悪いことが起こる可能性のある具体的な例です。

拡張モジュールをオンにすると、新しいインスタンスの重複がサイレントに追加される可能性があるため、単一のモジュールのインポートを追加または削除するだけではプログラムの意味を変更できないという特性が破られています。除去された。なぜそれが不愉快なのか分かりますが、私はそれがなぜ大騒ぎでひどいのか分かりません。

ボーナスの質問:私たちが有用ではあるが理論的には十分に根拠のない拡張機能の対象である限り、悪い出来事につながる可能性があるので、GeneralizedNewtypeDerivingはどのように同じ悪いラップを得られないのでしょうか?それは否定的な可能性がローカライズすることがより容易であるからです。何が問題を引き起こし、「それをしないでください」と言うのが見えやすいのでしょうか?

EDIT(注答えの矛先は、OverlappingInstancesにはあまり説明が必要IncoherentInstancesをしませ焦点を当てた場合、私は好むだろう。):同様の質問hereに良い答えもあります。

+5

'GeneralizedNewtypeDeriving'の悪さは実装上のバグです。この拡張機能については何も悪いことはありませんが、ghcは禁止する必要がある場合に許可します。 – augustss

+1

関連:http://stackoverflow.com/questions/10830757/is-there-a-list-of-ghc-extensions-that-are-considered-safe –

+2

@augustss、それは簡単ですか? http://hackage.haskell.org/trac/ghc/ticket/5498を参照してください。 Simonは、いつ禁止するべきかを判断するための単純な構文テストについては知らず、新しい理論的な作業と型チェッカーの安全性を高める必要があると述べています。 – glaebhoerl

答えて

18

特定のモジュールに余分なメソッド/クラスまたはインスタンスを追加することによって、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すぐAの次のインスタンス宣言を追加するモジュールB

で "こんにちは" と等しくありません。

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

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

モジュールBはまだコンパイルされていますが、今度はshouldEqualHello"hellohellohellohello"になります。最初に使用していたメソッドが変更されていないにもかかわらず、動作が変更されました。

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

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

+0

私は参照してください。それは基本的に私がこの問題で認めている問題ですが、なぜそれが悪いのかを説明してくれました。これは唯一の問題ですか? – glaebhoerl

+4

はい、「唯一の」本当の問題は、コードの合流性と理由を完全に失うことができるということです。 1つのモジュールで重複するすべてのインスタンスを慎重に定義している場合はうまく機能しますが、制約の種類を悪用して、より具体的でないインスタンスをより具体的なケースに渡す悪いことを行う方法があります。 –

+1

@EdwardKmettここで「合流」という言葉を使っていますか?ターム書き換えシステムと同じですか? – glaebhoerl

関連する問題