2011-04-27 3 views
4

Я новичок в Haskell. Я написал этот код:Не удалось вывести (Eq a) из контекста (...)

deleteDuplicates :: [a] -> [a] 
deleteDuplicates [] = [] 
deleteDuplicates (x:xs) 
     | x == (head xs)  = x : (deleteDuplicates (tail xs)) 
     | otherwise    = x : (head xs) : (deleteDuplicates (tail xs)) 

Что означает эта ошибка и почему это произошло? Я случайно сравниваю два разных типа?

set2.hs:10:3: 
    Could not deduce (Eq a) from the context() 
     arising from a use of `==' at set2.hs:10:3-16 
    Possible fix: 
     add (Eq a) to the context of 
     the type signature for `deleteDuplicates' 
    In the expression: x == (head xs) 
     In a stmt of a pattern guard for 
       the definition of `deleteDuplicates': 
      x == (head xs) 
    In the definition of `deleteDuplicates': 
     deleteDuplicates (x : xs) 
          | x == (head xs) = x : (deleteDuplicates (tail xs)) 
          | otherwise = x : (head xs) : (deleteDuplicates (tail xs)) 

ответ

17

Ваш тип подписи неправильно:

deleteDuplicates :: [a] -> [a] 

Это говорит ваша функция может работать со списками любого типа, a, но это не так! Вы позже позвоните:

x == (head xs) 

Таким образом, вы должны быть в состоянии сравнить свой тип для равенства. Значение подписи должно быть:

deleteDuplicates :: Eq a => [a] -> [a] 

В такие времена это хорошо, чтобы удалить явный тип подписи, загрузить функцию в GHCi и обнаружить какой тип интерпретатор считает, что должно быть (через :t deleteDuplicates).

Больше Bugs

Кроме того, ваше использование head есть плохая идея. head является частичной функцией и сбой при xs == []. Я предлагаю вам расширить поиск по шаблону:

deleteDuplicates (x1:x2:xs) 
    | x1 == x2 = ... 
    | otherwise = x1 : deleteDuplicates (x2:xs) 

заметить также исправление в otherwise случае. Вы пропустили x2, но что, если x2 соответствует следующему элементу в списке? Что-то вроде [1,2,2,3] было бы обнаружено 1 /= 2, а затем рекурсия получила бы список [2,3] - oops!

+0

Вы совершенно правы в чем-то вроде '[1, 2, 2, 3]', не получив список со всеми удаленными дубликатами. Виноват. Элемент 'Eq a =>' для меня является новым ... так что единственное, что делает, это принуждение к тому, чтобы элементы типа 'a' были сопоставимы? – Pieter

+0

Pieter: В принципе, да. Это «ограничение типа стека». Функция '==' объявляется в 'Eq' typeclass, поэтому ее можно использовать только в экземплярах Eq. –

+0

@ Питер: сопоставим для равенства, да. 'Eq a =>' говорит, что 'a' должен быть экземпляром класса type' Eq'. Класс type указывает интерфейс, который реализует экземпляр.Класс 'Eq' предоставляет две функции:' (==) 'и' (/ =) ', как с типом' a -> a -> Bool'. Другие типы классов будут предоставлять другие функции, например, 'Ord' предоставляет тесты менее, чем и более, и аналогичные. –

1

Выражение

x == (head xs) 

== требует, чтобы быть определены на членов xs, что означает a должен быть экземпляром класса типов Eq. Изменение типа подписи вашей функции на

deleteDuplicates :: Eq a => [a] -> [a] 
2

компилятор говорит вам, что только из сигнатуры типа она не может работать, если a является InstanceOf Eq.

deleteDuplicates :: Eq a => [a] -> [a] 

Вы должны сказать компилятору, что a является экземпляром класса Eq типа, упоминая его в подписи.

Смежные вопросы