Предположим, что я пишу тип данных для представления координаты в декартовой системе координат. Я хотел бы определить функции этого типа данных и использовать проверку типа Haskell для предотвращения смешивания чисел, лежащих на оси х с числами на оси y.Пример экземпляра класса с более ограничительной сигнатурой
Вот определение типа данных, с типом фантома, который отслеживает координатной оси и две функции для построения значения:
data X
data Y
newtype Coordinate axis = Coordinate Int64 deriving (Show)
newX :: Int64 -> Coordinate X
newX = Coordinate
newY :: Int64 -> Coordinate Y
newY = Coordinate
Давайте определим функцию скольжения, которая скользит координата, либо по значению Int или другой Значение координаты. В первом случае координата должна сохранить свою ось и во втором случае оба аргумента должны иметь ту же ось:
slideByInt :: Coordinate a -> Int64 -> Coordinate a
slideByInt (Coordinate x) y = Coordinate $ x + y
slideByCoord :: Coordinate a -> Coordinate a -> Coordinate a
slideByCoord (Coordinate x) (Coordinate y) = Coordinate (x + y)
Это все прекрасно работает, и это мешает мне перепутать X и оси Y в функциях, которые манипулируют координаты.
Мой вопрос: как бы я обертываю slideByInt
и slideByCoord
функциональность за классом, так что я могу иметь только функцию slide
. Это составляет:
class Slide a where
slide :: Coordinate x -> a -> Coordinate x
instance Slide Int64 where
slide (Coordinate x) y = Coordinate (x + y)
instance Slide (Coordinate x) where
slide (Coordinate x) (Coordinate y) = Coordinate (x + y)
, но это не так, типа безопасной, как функции автономных: slide (newX 1) (newY 1)
не должен набрать проверить! Как можно было бы исправить это, в некотором смысле, как я могу сделать экземпляр для двух координат менее разрешительным, чем это?
Я пробовал с кучей расширений (InstanceSigs, FunctionalDependencies, ограничения типов ...), но ничего не компилируется, и сложно сказать, полностью ли это, или мне просто нужно немного изменить мой код.
Спасибо ...
Это интересный вопрос о трюке типа. Тем не менее, в вашем конкретном случае использования вы можете подумать о том, чтобы отбросить класс «Слайд», предоставив «Coordinate x» экземпляр «Num» и записывая «newX 2 + newX 3» или даже «2 + 3 :: Coordinate X» , – duplode
@duplode Я переводил код Python и хотел бы сохранить тот же API, но добавьте некоторую безопасность типа сверху.Теперь, когда я вижу ответ, на самом деле это не выглядит ужасно сложным (по сравнению с некоторыми другими вещами, которые я видел:>). – kmelva