Сокращение типового класса Haskell
Вопрос
Итак, у меня есть пара классов типов, которые я буду часто использовать вместе, и я хочу избежать указания обоих каждый раз.По сути, вместо того, чтобы ставить
:: (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'
Так есть ли способ сделать это?
Решение
С расширением ConstraintKinds, представленным в GHC 7.4, ограничения теперь являются типами типа Constraint
, поэтому вы можете использовать синонимы обычных типов, чтобы получить то, что вы хотите:
{-# LANGUAGE ConstraintKinds #-}
type OrdFractional a = (Ord a, Fractional a)
Другие советы
То, что вы хотите, это псевдоним класса. Есть предложение добавить его в Haskell по адресу http://repetae.net/recent/out/classalias. .html р>
Когда компилятор говорит " Использовать -XF FlexibleInstances
", попробуйте добавить
{-# LANGUAGE FlexibleInstances #-}
к началу вашего исходного кода (и прочитайте документацию, чтобы узнать, что он делает, конечно!).
В этом конкретном случае это заставит ваш код работать:
{-# LANGUAGE FlexibleInstances, UndecidableInstances #-}
Гибкие экземпляры требуются для включения контекста = >
в заголовке экземпляра, а неразрешимые экземпляры требуются, потому что компилятор при обработке контекста OrdFractional a
, может прекратить добавление Fractional a
и Ord a
в контекст, что напрямую не помогает с окончательным определением a
, и, соответственно, под ужасным ужасом обстоятельства, проверка типов может отличаться; компилятору это действительно не нравится. (Вам, вероятно, не понравится, если компилятор будет работать вечно или не хватит памяти).
Нет.
Ваше решение суперкласса, подразумевающее другие классы, наиболее близко к тому, что вы хотите, и возможно в Haskell.Несмотря на то, что для этого требуется создание вручную экземпляров этого нового класса, он иногда используется, например, в переписывание библиотека.
Как упоминал CesarB, псевдонимы классов делают то, что вы хотите (и даже больше), но это всего лишь предложение, которое существует уже много лет и никогда не было реализовано, вероятно, из-за множества проблем с ним.Вместо этого появлялись различные другие предложения, но ни одно из них также не было реализовано.(Список этих предложений см. здесь. Хаскеллвики-страница.) Один из проектов на Хак5 было изменить GHC, включив в него небольшое подмножество псевдонимов классов, называемых контекстные синонимы (который делает именно то, о чем вы здесь просите, и не более того), но, к сожалению, он так и не был закончен.