Как сопоставить жесткие типы в экземпляре класса типов?

StackOverflow https://stackoverflow.com/questions/1946973

  •  20-09-2019
  •  | 
  •  

Вопрос

Я подумал, что попробую смоделировать численное интегрирование векторных величин различной размерности, и решил, что классы типов — это то, что мне нужно.Мне нужно было что-то, чтобы определить разницу между двумя значениями и масштабировать ее с помощью множителя (чтобы получить производную), а также иметь возможность использовать функцию расстояния.

На данный момент у меня есть:

class Integratable a where
    difference :: a -> a -> a
    scale :: Num b => a -> b -> a
    distance :: Num b => a -> a -> b

data Num a => Vector a = Vector1D a | Vector2D a a

instance Num a => Integratable (Vector a) where
    difference (Vector1D x1) (Vector1D x2) = Vector1D (x1 - x2)
    scale (Vector1D x) m = Vector1D (x * m)
    distance (Vector1D x1) (Vector1D x2) = x1 - x2
    difference (Vector2D x1 y1) (Vector2D x2 y2) = Vector2D (x1 - x2) (y1 - y2)
    scale (Vector2D x y) m = Vector2D (x * m) (y * m)
    distance (Vector2D x1 y1) (Vector2D x2 y2) = sqrt((x1-x2)*(x1-x2)
                                                      + (y1-y2)*(y1-y2))

К сожалению, здесь есть пара проблем, которые я не понял, как решить.Во-первых, scale функция выдает ошибки.GHC не может этого сказать m и x совместимы, поскольку жесткое ограничение типа Num дается в экземпляре в одном случае, а в Vector напишите в другом случае...Есть ли способ указать это x и m одного типа?

(На самом деле я понимаю, что даже если x и m оба Num, они могут быть не такой же Num.Как я могу это указать?Если я не могу понять это с помощью Num, с использованием Double было бы хорошо, но я бы предпочел оставить это в общих чертах.)

Есть аналогичная проблема с distance.Попытка указать, что тип возвращаемого значения Num терпит неудачу, поскольку в определении экземпляра нельзя указать, что a будет содержать значения, совместимые с b.

Это было полезно?

Решение

РЕДАКТИРОВАТЬ: Мне кажется теперь, что статья о функциональные зависимости из HaskellWiki предоставляет ключевую информацию в лучшей форме, которую я могу найти, поэтому я бы предложил прочитать ее вместо моего ответа здесь.Однако я не удаляю остальной контент, поскольку он ясно показывает (надеюсь), почему FD здесь полезны.


Помимо проблемы с группировкой определений, на которую указал Дэйв...

(На самом деле я понимаю, что даже если x и m оба Num, они могут быть не такой же Num.Как я могу это указать?Если я не могу понять это с помощью Num, с использованием Double было бы хорошо, но я бы предпочел оставить это в общих чертах.)

Это, на самом деле, основная проблема.Вы не можете умножить Integer по Float, сказать.По сути, вам нужно x и m в масштабе быть одного типа.

Аналогичная проблема возникает и с расстоянием, но с дополнительными сложностями, sqrt нуждается в Floating аргумент.Думаю, вам тоже нужно где-то об этом упомянуть.(Скорее всего, на экземпляре, я думаю).

РЕДАКТИРОВАТЬ: ОК, поскольку sqrt работает только на Floating значения, вы можете создать класс типов для тех, которые нужно преобразовать Floats для Doubles, когда это необходимо.

Другая идея предполагает наличие класса типов Scalable:

data Vector a = Vector1D a | Vector2D a a deriving (Show)                       

class Scalable a b | a -> b where
  scale :: a -> b -> a

instance (Num a) => Scalable (Vector a) a where
  scale (Vector1D x)   m = (Vector1D (x * m))
  scale (Vector2D x y) m = (Vector2D (x * m) (y * m))

При этом используется так называемая функциональная зависимость в определении Scalable.Фактически, пытаясь запомнить синтаксис этого, я нашел эта ссылка...Поэтому я думаю, вам следует игнорировать мою неудовлетворительную попытку помочь и прочитать там качественную информацию.;-)

Я думаю, вы сможете использовать это для решения своей первоначальной проблемы.

Другие советы

Я думаю, чтобы исправить вторую ошибку, вам нужно изменить порядок определений в объявлении экземпляра.Сначала имеем два уравнения для difference, то уравнения для scale, то оба для distance.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top