Haskell Typeclass сокращает
Итак, у меня есть пара типов, которые я буду использовать много вместе, и я хочу избежать указания обоих раз. В принципе, вместо размещения
:: (Ord a, Fractional a, Ord b, Fractional b, ... Ord z, Fractional z) =>
в начале всех спецификаций моего типа, я предпочел бы поставить
:: (OrdFractional a, OrdFractional b, ... OrdFractional z)
Итак, моя первоначальная идея о том, как это сделать, заключается в просто объявлении нового класса
module Example where
class (Fractional a, Ord a) => OrdFractional a
example :: (OrdFractional a, OrdFractional b) => (a,b) -> (a,b) -> (a,b) -> Bool
example (x1,y1) (x2,y2) (x3,y3) = (x1/x2 < x2/x3) && (y1/y2 < y2/y3)
Но это не сработало автоматически, как мне хотелось бы:
% ghci
Prelude> :l Example.hs
Ok, modules loaded: Example.
Prelude Example> example (1::Float,3::Float) (2,2) (3,1)
<interactive>:1:0:
No instance for (OrdFractional Float)
arising from a use of `example' at <interactive>:1:0-39
Possible fix:
add an instance declaration for (OrdFractional Float)
In the expression: example (1 :: Float, 3 :: Float) (2, 2) (3, 1)
In the definition of `it':
it = example (1 :: Float, 3 :: Float) (2, 2) (3, 1)
Вручную создание экземпляров похоже на перетаскивание, поэтому, я подумал, что могу попытаться автоматически создать экземпляры:
module Example where
class OrdFractional a
instance (Fractional a, Ord a) => OrdFractional a
example :: (OrdFractional a, OrdFractional b) => (a,b) -> (a,b) -> (a,b) -> Bool
example (x1,y1) (x2,y2) (x3,y3) = (x1/x2 < x2/x3) && (y1/y2 < y2/y3)
Но компилятору это не понравилось:
ghc -c Example.hs
Example.hs:4:0:
Illegal instance declaration for `OrdFractional a'
(All instance types must be of the form (T a1 ... an)
where a1 ... an are 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 `OrdFractional a'
Как я могу это сделать?
Ответы
Ответ 1
С расширением ConstraintKinds, введенным в GHC 7.4, ограничения теперь являются типами вида Constraint
, поэтому вы можете использовать синонимы обычного типа, чтобы получить то, что вы хотите:
{-# LANGUAGE ConstraintKinds #-}
type OrdFractional a = (Ord a, Fractional a)
Ответ 2
Что вы хотите - это псевдоним класса. Есть предложение добавить его в Haskell по адресу http://repetae.net/recent/out/classalias.html
Ответ 3
Когда компилятор говорит "Use -XFlexibleInstances
", вы должны попробовать добавить
{-# LANGUAGE FlexibleInstances #-}
в начало вашего источника (и, конечно же, прочитайте документацию, чтобы узнать, что он делает).
В этом конкретном случае это заставит ваш код работать:
{-# LANGUAGE FlexibleInstances, UndecidableInstances #-}
Для включения контекста =>
в головке экземпляра требуются гибкие экземпляры, и требуются нерегулярные экземпляры, потому что компилятор при обработке контекста OrdFractional a
может завершить добавление Fractional a
и Ord a
к контекст - который непосредственно не помогает с окончательным определением a
, и при подходящих ужасных обстоятельствах проверка типов может расходиться; компилятору это действительно не нравится. (Вероятно, вам это не понравилось бы, если бы компилятор продолжался вечно или закончился нехваткой памяти.)
Ответ 4
Нет.
Ваше решение суперкласса, подразумевающее другие классы, является самым близким к тому, что вы хотите, что возможно в Haskell. Хотя для этого требуются ручные экземпляры этого нового класса, он иногда используется, например, в библиотеке rewriting.
Поскольку упомянутые псевдонимы классов CesarB делают то, что вы хотите (и многое другое), но это всего лишь предложение, которое существует уже много лет и никогда не было реализовано, возможно, потому, что с ним много проблем. Вместо этого появилось множество других предложений, но ни одно из них не было реализовано. (Список этих предложений см. В этой странице Haskellwiki.) Один из проектов на Hac5 должен был изменить GHC, чтобы включить небольшое подмножество псевдонимов классов, называемое контекстными синонимами (которые делают именно то, что вы просите здесь, и не более того), но, к сожалению, это никогда не заканчивалось.