Подтвердить что ты не робот

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'

Как я могу это сделать?

4b9b3361

Ответ 1

С расширением ConstraintKinds, введенным в GHC 7.4, ограничения теперь являются типами вида Constraint, поэтому вы можете использовать синонимы обычного типа, чтобы получить то, что вы хотите:

{-# LANGUAGE ConstraintKinds #-}

type OrdFractional a = (Ord a, Fractional a)

Ответ 3

Когда компилятор говорит "Use -XFlexibleInstances", вы должны попробовать добавить

{-# LANGUAGE FlexibleInstances #-}

в начало вашего источника (и, конечно же, прочитайте документацию, чтобы узнать, что он делает).

В этом конкретном случае это заставит ваш код работать:

{-# LANGUAGE FlexibleInstances, UndecidableInstances #-}

Для включения контекста => в головке экземпляра требуются гибкие экземпляры, и требуются нерегулярные экземпляры, потому что компилятор при обработке контекста OrdFractional a может завершить добавление Fractional a и Ord a к контекст - который непосредственно не помогает с окончательным определением a, и при подходящих ужасных обстоятельствах проверка типов может расходиться; компилятору это действительно не нравится. (Вероятно, вам это не понравилось бы, если бы компилятор продолжался вечно или закончился нехваткой памяти.)

Ответ 4

Нет.

Ваше решение суперкласса, подразумевающее другие классы, является самым близким к тому, что вы хотите, что возможно в Haskell. Хотя для этого требуются ручные экземпляры этого нового класса, он иногда используется, например, в библиотеке rewriting.

Поскольку упомянутые псевдонимы классов CesarB делают то, что вы хотите (и многое другое), но это всего лишь предложение, которое существует уже много лет и никогда не было реализовано, возможно, потому, что с ним много проблем. Вместо этого появилось множество других предложений, но ни одно из них не было реализовано. (Список этих предложений см. В этой странице Haskellwiki.) Один из проектов на Hac5 должен был изменить GHC, чтобы включить небольшое подмножество псевдонимов классов, называемое контекстными синонимами (которые делают именно то, что вы просите здесь, и не более того), но, к сожалению, это никогда не заканчивалось.