6

マルチパラメータ型クラスを理解しようとしていますが、インスタンス宣言を取得できません。2 つのベクトルで内積を実行できるように、Vector 型の InnerProductSpace 型クラスを作成しようとしています。まず、各ベクトルの最初の要素を乗算できるかどうかを確認したかっただけです。これが私のコードです

class InnerProductSpace a b c where
dot :: a -> b -> c

data Vector = Vector [Double]
  deriving (Show)

instance InnerProductSpace Vector Vector Double where
  dot (Vector a) (Vector b) = (head a * head b)

ドット関数を使用しようとした後のエラーは

No instance for (InnerProductSpace Vector Vector c0)
  arising from a use of `dot'
The type variable `c0' is ambiguous
Possible fix: add a type signature that fixes these type variable(s)
Note: there is a potential instance available:
  instance InnerProductSpace Vector Vector Double
    -- Defined at Vector.hs:8:10
Possible fix:
  add an instance declaration for
  (InnerProductSpace Vector Vector c0)
In the expression: dot a b
In an equation for `it': it = dot a b

私は何を間違えましたか?ありがとう!

4

2 に答える 2

7

問題は、コンパイラが知っていることから正しいインスタンスを選択する方法を知らないことです。次のようなものを試してみると

vectorA `dot` vectorA

コンパイラはdot、その型がdot :: Vector -> Vector -> c0. 残念ながら、それだけでは十分な情報ではありません — <code>c0 は何でもかまいませんし、コンパイラは、インスタンスが 1 つしかないからといって、それが正しいものであるに違いないと想定することはありません (これは、オープン ワールドの仮定に関連しています。コンパイラがまだ認識していない別のインスタンスである可能性があるため、単にエラーをスローすることを好みます)。結果がどうあるべきかをコンパイラに明示的に伝えることで、それを回避できます

vectorA `dot` vectorB :: Double

しかし、これは退屈で、数値型では多くの場合失敗する可能性があります。これらの型はジェネリックでもあることが多いからです。たとえば、ここでは のどのインスタンスNumが使用されていますか?

(vectorA `dot` vectorB) + 3

であることはわかっていますDoubleが、コンパイラはそれを証明できません。

1 つの解決策は、@AndrewC がコメントで提案しているように、型ファミリを使用することです。私は実際にそれを強くお勧めします。実際に目にするもう 1 つの解決策は、Functional Dependencies です。これらはこのように書かれています

class InnerProductSpace a b c | a b -> c where
  dot :: a -> b -> c

コンパイラへの約束を伴うように変換します:「知っaていることbは、一意に識別するのに十分な情報cです」コンパイラはあなたを正直に保つだけでなく、その約束に矛盾するインスタンスを書くことを防ぎます.

instance InnerProductSpace Vector Vector Double where
  dot (Vector a) (Vector b) = (head a * head b)

instance InnerProductSpace Vector Vector Float where
  dot (Vector a) (Vector b) = (head a * head b)

---

/Users/tel/tmp/foo.hs:10:10:
    Functional dependencies conflict between instance declarations:
      instance InnerProductSpace Vector Vector Double
        -- Defined at /Users/tel/tmp/foo.hs:10:10
      instance InnerProductSpace Vector Vector Float
        -- Defined at /Users/tel/tmp/foo.hs:13:10

Doubleしかし、promise は、前の例での問題を解決するのに十分な情報をコンパイラーに提供します。

Main*> (Vector [1,2,3]) `dot` (Vector [2,3,4]) + 3.0
5
于 2013-08-06T23:28:33.287 に答える