Вопрос

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

:: (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, включив в него небольшое подмножество псевдонимов классов, называемых контекстные синонимы (который делает именно то, о чем вы здесь просите, и не более того), но, к сожалению, он так и не был закончен.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top