2012-04-11 3 views
4

Я пытаюсь реализовать простую функцию мин, которая принимает два параметра & возвращает истину, если первая должна появиться перед вторым в отсортированном порядке, и False в противном случае:Haskell и Ord

min :: a -> a -> Bool 
min a b = if a < b then True else False 

я получаю:

No instance for (Ord a) 
arising from a use of `<' 
+11

if foo then True else False всегда можно переписать как просто foo – Sarah

+0

Спасибо за это! –

+2

И в следующий раз, если у вас есть сомнения, вы можете просто оставить аннотацию типа в верхней части и спросить компилятор во многих случаях. Таким образом: t min дает мне правильный тип с ограничением Ord, когда я запрашиваю ghci об этом. – Sarah

ответ

7

Вам нужен тип ограничения для < работы:

min :: Ord a => a -> a -> Bool 
--  ^^^^^ 
+0

Было бы полезно рассказать им, почему - что такое ограничение типа. – amindfv

+0

@amindfv: dave4420 уже сделал это, и я поддержал его ответ. –

25

Если вас look at the documentation, вы увидите, что тип для (<) дается как

(<) :: a -> a -> Bool 

Это заблуждение!

Объявление типа появляется в определении класса типов:

class Eq a => Ord a where ... 

Так полный типа является

(<) :: Ord a => a -> a -> Bool 

Кстати, если вы спросите GHCi какого типа (<) «s это, он получит это право ,

Prelude> :t (<) 
(<) :: (Ord a) => a -> a -> Bool 

Также отметим, что уже функция называется min, в том же класса типов.

min :: Ord a => a -> a -> a 

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


Наконец, теперь у вас есть

min :: Ord a => a -> a -> Bool 
min a b = if a < b then True else False 

Как отмечает Сара, if blah then True else False такой же, как blah , так что вы можете упростить для более четкого

min :: Ord a => a -> a -> Bool 
min a b = a < b 

Теперь операторы в Haskell являются только функции с забавными названиями --- это то же самое, как

min :: Ord a => a -> a -> Bool 
min a b = (<) a b 

Мы можем упростить это далее:

min :: Ord a => a -> a -> Bool 
min = (<) 

Так что ваш min это просто другое название для (<). Почему бы просто не использовать оригинал < вместо min?

+0

@ gonzoc0ding: Дэйв абсолютно прав (+1 кстати) –

+2

+1 пошаговое объяснение от 'min a b = if a nimi

8

Есть уже два ответа на это, но я думаю, что есть важный момент отсутствует:

причина, что вам нужно (Ord a) => в вашей сигнатуре типа является то, что вам нужно, чтобы ограничить типы, которые разрешены «в «твоя функция.

Когда я определяю функцию function :: a -> a, я говорю, что моя функция примет данные любого типа и вернет значение того же типа.

Хорошим примером является head :: [a] -> a - данный список любой тип, голова вернет первый аргумент списка. Это потому, что голова действительно не «касается» самих данных, поэтому совершенно не имеет значения, что это такое.

Однако, ваша ситуация не так: представьте себе, у нас есть тип данных Страны:

data Countries = USA | Nigeria | China | Canada -- yes, I know there are a few missing 

Это не имеет никакого смысла говорить min USA Canada или USA < Canada.

Следовательно, вы должны ограничить свои функции типами, которые можно сравнить таким образом: типы, которые имеют экземпляры класса (что означает упорядоченное). То, как вы их ограничиваете, написано (Ord a) => перед вашей подписью типа.

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