6

リニアと呼ばれるNumのスーパークラスを作りたい

class Linear a where 
  add :: a -> a -> a

instance (Num a) => Linear a where
  add = (+)

エラーが発生します:

Illegal instance declaration for `Linear a'
  (All instance types must be of the form (T a1 ... an)
   where a1 ... an are *distinct type variables*,
   and each type variable appears at most once in the instance head.
   Use -XFlexibleInstances if you want to disable this.)
In the instance declaration for `Linear a'

私が理解していることから、線についての何かinstance (Num a) => Linear a whereが間違っています。(フラグを使用するとコンパイルされます-XFlexibleInstances -XUndecidableInstances:)

それらの恐ろしい旗を使わずにこれを達成する方法はありますか?(そして、上記のコードについて決定不可能なのは世界で何ですか??)

更新:線形に多項式タイプを追加しました。

newtype Polynomial a = Polynomial (a,[a]) deriving Show-- list of coeffients 

instance (Linear a) => Linear (Polynomial a)
         where 
           add (Polynomial (c1, l1)) (Polynomial (c2, l2))
             = Polynomial (add c1 c2, zipWith (add) l1 l2)

p1 = Polynomial (0, [3,4,5])
p2 = Polynomial (0, [])

main = putStrLn $ show ((add p1 p2):: Polynomial Int)

多項式を追加した後、それらのフラグでさえコンパイルされず、エラーが発生します。

Overlapping instances for Linear (Polynomial Int)
  arising from a use of `add'
Matching instances:
  instance Num a => Linear a -- Defined at Algebra.hs:22:10-28
  instance Linear a => Linear (Polynomial a)
    -- Defined at Algebra.hs:25:10-44
In the first argument of `show', namely
  `((add p1 p2) :: Polynomial Int)'
In the second argument of `($)', namely
  `show ((add p1 p2) :: Polynomial Int)'
In the expression: putStrLn $ show ((add p1 p2) :: Polynomial Int)
4

2 に答える 2

10

言語レポートではフォームのインスタンスは許可されていないinstance Class a where...ため、回避する唯一の方法FlexibleInstances(少なくとも怖くない)は、newtypeラッパーを使用することです。

newtype LinearType a = Linear a

liftLin2 :: (a -> b -> c) -> LinearType a -> LinearType b -> LinearType c
liftLin2 op (Linear x) (Linear y) = Linear (op x y)

instance Num a => Linear (LinearType a) where
    add = liftLin2 (+)

うん。

UndecidableInstances制約Num aがインスタンスヘッドより小さくないため(同じ型変数を同じ回数使用する)、コンパイラは型チェックが終了することを事前に証明できないため、拡張が必要です。したがって、プログラムを受け入れるために型チェックが終了することをコンパイラに約束する必要があります(型チェッカーの再帰深度を制御するコンテキストスタックを持つGHCでは実際にはループしないため、型チェックが行われない場合はすぐに終了すると、「コンテキストスタックを超えました」でコンパイルに失敗します。サイズは-fcontext-stack=N)で設定できます。

この拡張機能は、実際よりもはるかに恐ろしいように聞こえます。基本的には、コンパイラに「信頼してください、型チェックは終了します」と伝えるだけなので、コンパイラは終了することを確認せずに起動します。

しかし、あなたは何を達成しようとしていますか?あなたが現在持っているもの、

instance (Num a) => Linear a where
  add = (+)

「すべての型はLinearのインスタンスであり、Numのインスタンスではない型でaddを使用しようとすると、コンパイル時エラーになります」と述べています。あまり役に立ちません。Numを有効にしない限り、OverlappingInstancesに属していないタイプのインスタンスをさらに追加することはできませんIncoherentInstances。そして、それらの拡張機能恐ろしいものです。それらはほとんど使用されるべきではなく、自分が何をしているのかを知っている場合にのみ使用されるべきです。

于 2012-03-26T11:19:49.120 に答える
3

スーパークラスの宣言を許可する提案があります。AFAIKはまだ実装されていませんが、GHCはオープンソースであるため、必要に応じて変更できます;)

于 2012-03-26T11:48:00.737 に答える