3

私の問題は、Haskell のポリモーフィズムに関する非常に限られた知識を、他の言語からのオーバーロードやテンプレート化などと混同していることだと思います。前回の質問の後、概念をよりよく理解していると思いましたが、もう一度試してみると、そうではないようです!

とにかく、一般的な距離関数を実装しようとしています。それは簡単でした:

euclidean :: Integral a => [a] -> [a] -> Double
euclidean a b = sqrt . sum $ zipWith (\u v -> (u - v)^2) x y
                where x = map fromIntegral a
                      y = map fromIntegral b

ここで、これを 2 つのベクトル型に適用したいと思います (議論のために、再定義することはできません)。

type Vector1 = Integer
data Vector2 = Vector2 Integer Integer

前の質問への回答を読んだ後、パターン マッチングを使用することにしました。

d :: a -> a -> Double
d (Vector2 x1 y1) (Vector2 x2 y2) = euclidean [x1, y1] [x2, y2]
d a b = euclidean [a] [b]

これは失敗します:

Couldn't match expected type `a' with actual type `Vector2'
  `a' is a rigid type variable bound by
      the type signature for d :: a -> a -> Double at test.hs:11:6
In the pattern: Vector2 x1 y1
In an equation for `d':
    d (Vector2 x1 y1) (Vector2 x2 y2) = euclidean [x1, y1] [x2, y2]

ですから、気を取り直して、型クラスをもう一度試してみることにします。

{-# LANGUAGE FlexibleInstances #-}

class Metric a where
  d :: a -> a -> Double

instance Metric Vector1 where
  d a b = euclidean [a] [b]

instance Metric Vector2 where
  d (Vector2 x1 y1) (Vector2 x2 y2) = euclidean [x1, y1] [x2, y2]

This compiles and works when the type you're feeding into d is known in advance. However, in my case, I have written another function, which calls d, where the type could be either (it's determined at runtime). This fails:

No instance for (Metric a) arising from a use of `d'
Possible fix:
  add (Metric a) to the context of
    the type signature for someFunction :: [a] -> [a] -> [a]
In the expression: d c x
In the expression: (x, d c x)
In the first argument of `map', namely `(\ x -> (x, d c x))'

From my limited understanding of the answers to my previous question, I believe the reason for this is because my type class has holes in it, which leads the type inferencer into an indeterminable state.

At this point, I'm at a bit of a loss: neither parametric nor ad hoc polymorphism has solved my problem. As such, my solution was this mess:

someFunction1 :: [Vector1] -> [Vector1] -> [Vector1]
-- Lots of code
where d a b = euclidean [a] [b]

someFunction2 :: [Vector2] -> [Vector2] -> [Vector2]
-- Exactly the same code
where d (Vector2 x1 y1) (Vector2 x2 y2) = euclidean [x1, y1] [x2, y2]

This doesn't seem right. What am I missing?

4

2 に答える 2