Добавление ограничений типа в контекст объявлений экземпляров в Haskell - PullRequest
7 голосов
/ 17 ноября 2010

Я пытаюсь представить взвешенные края.В конце концов я хочу, чтобы OutE был экземпляром Eq и Ord с ограничением, что etype является экземпляром Eq и Ord.Предположим, у меня есть следующий файл как temp.hs:

data (Ord etype)=> OutE vtype etype = OutE {destVertex:: vtype, edgeValue::etype}

applyFunBy accessor ordfun = (\x y -> (ordfun (accessor x) (accessor y)))

instance Eq (OutE vtype etype) where
    --(==) :: Ord etype => (OutE vtype etype) -> (OutE vtype etype) -> Bool
    --(/=) :: Ord etype => (OutE vtype etype) -> (OutE vtype etype) -> Bool
    (==) = applyFunBy edgeValue (==)
    (/=) = applyFunBy edgeValue (/=)

, когда я загружаю его в ghci, я получаю следующие ошибки:

temp.hs:10:19:
    Could not deduce (Ord etype)
      from the context (Eq (OutE vtype etype))
      arising from a use of `edgeValue' at temp.hs:10:19-27
    Possible fix:
      add (Ord etype) to the context of the instance declaration
    In the first argument of `applyFunBy', namely `edgeValue'
    In the expression: applyFunBy edgeValue (==)
    In the definition of `==': == = applyFunBy edgeValue (==)

temp.hs:11:19:
    Could not deduce (Ord etype)
      from the context (Eq (OutE vtype etype))
      arising from a use of `edgeValue' at temp.hs:11:19-27
    Possible fix:
      add (Ord etype) to the context of the instance declaration
    In the first argument of `applyFunBy', namely `edgeValue'
    In the expression: applyFunBy edgeValue (/=)
    In the definition of `/=': /= = applyFunBy edgeValue (/=)
Failed, modules loaded: none.

Если включить строки для сигнатур типов для(==) и (\ =) я получаю:

temp.hs:6:1:
    Misplaced type signature:
    == ::
      (Ord etype) => (OutE vtype etype) -> (OutE vtype etype) -> Bool

temp.hs:7:1:
    Misplaced type signature:
    /= ::
      (Ord etype) => (OutE vtype etype) -> (OutE vtype etype) -> Bool

Ответы [ 2 ]

6 голосов
/ 17 ноября 2010

Вы ограничили etype значением Ord в определении OutE:

data (Ord etype) => OutE vtype etype = ...

Но в случае Eq вы фактически пытаетесь определить экземпляр для any etype без ограничений.

instance Eq (OutE vtype etype) where

Конечно, это не работает, поскольку OutE сам по себе только что определен для Ord etype s, поэтому вам придется добавить ограничение класса типовк определению экземпляра.

instance (Ord etype) => Eq (OutE vtype etype) where

Обратите внимание, что для работы класса типов достаточно одного определения == или /=.


Обратите внимание, что частопроще и поэтому считается, что лучше стиль не иметь ограничения класса типов для data -типов, а только для экземпляров / методов, которые фактически требуют функциональности класса типов.

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

Возьмем, например, какой-то упорядоченный тип карты Ord key => Map key value.

Что еслимы просто хотим перечислить все ключи?Или получить количество элементов?Нам не нужно, чтобы ключи были Ord для них, так почему бы просто не оставить карту неограниченной с помощью простого

getKeys :: Map key value -> [key]
getLength :: Map key value -> Int

и просто добавить класс типов, когда он нам действительно нужен в такой функции, как

insert :: Ord key => key -> value -> Map key value
2 голосов
/ 17 ноября 2010
data (Ord etype)=> OutE vtype etype = OutE {destVertex:: vtype, edgeValue::etype}

Первый выпуск: это плохой стиль. Ваши объявления типов данных не должны иметь ограничений. Оставьте ограничения для функций, как это делает пакет контейнеров.

instance Eq (OutE vtype etype) where

Второй «выпуск». Вы можете просто добавить deriving (Eq) после объявления данных. Я предполагаю, что вы знаете это и пишете экземпляр явно для вашего собственного обучения (хорошо для вас) ...

instance Eq (OutE vtype etype) where
    (==) = applyFunBy edgeValue (==)
    (/=) = applyFunBy edgeValue (/=)

Третья проблема: вы не можете сравнивать значения капитала, если они относятся к классу Eq. Итак, вы хотите сказать, что etype ограничено уравнением:

instance (Eq etype) => Eq (OutE vtype etype) where
    (==) = applyFunBy edgeValue (==)
    (/=) = applyFunBy edgeValue (/=)

В-четвертых, вам на самом деле не нужно писать экземпляр для (==) и (/ =). Значения по умолчанию будут работать после определения одного из них.

...