Сокращения в Haskell Typeclass - PullRequest
       12

Сокращения в Haskell Typeclass

22 голосов
/ 20 ноября 2008

Итак, у меня есть пара классов типов, которые я буду часто использовать вместе, и я хочу избегать указания обоих типов каждый раз. В основном вместо того, чтобы поставить

:: (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'

Так есть ли способ сделать это?

Ответы [ 4 ]

32 голосов
/ 29 ноября 2012

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

{-# LANGUAGE ConstraintKinds #-}

type OrdFractional a = (Ord a, Fractional a)
11 голосов
/ 21 ноября 2008

То, что вы хотите, это псевдоним класса. Есть предложение добавить его в Haskell на http://repetae.net/recent/out/classalias.html

10 голосов
/ 03 июля 2009

Когда компилятор говорит "Use -XFlexibleInstances", попробуйте добавить

{-# LANGUAGE FlexibleInstances #-}

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

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

{-# LANGUAGE FlexibleInstances, UndecidableInstances #-}

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

3 голосов
/ 03 июля 2009

номер

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

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

...