#haskell #data-structures #types
#haskell #структуры данных #типы
Вопрос:
Я пытался написать небольшой файл, чтобы опробовать структуру данных, подобную пакету. Пока что мой код выглядит следующим образом:
data Fruit = Apple | Banana | Pear deriving (Eq, Show)
data Bag a = EmptyBag | Contents [(a, Integer)]
emptyBag :: Bag a
emptyBag = EmptyBag
unwrap :: [a] -> a
unwrap [x] = x
isObject theObject (obj, inte) = theObject == obj
count :: Bag a -> a -> Integer
count (Contents [xs]) theObject = snd (unwrap (filter (isObject theObject) [xs]))
count EmptyBag _ = 0
Но когда я пытаюсь запустить его, я получаю ошибку
Не удалось вывести (Eq a) из контекста ()
возникает из-за использования ‘isObject’ в ….
Принимая во внимание, что когда я извлекаю функцию count и вызываю snd(unwrap(filter (isObject Banana) [(Apple, 1),(Banana, 2)])), она с радостью возвращает 2.
Любые подсказки о том, почему это так, или советы по написанию такого рода структуры данных были бы высоко оценены.
Комментарии:
1. В
EmptyBag
конструкторе нет необходимости; используйтеContents []
вместо этого.2.
count
также произойдет сбой при попытке сделать что-то вроде,count (Contents [(Banana,2),(Apple,3)]) Apple
поскольку[xs]
совпадения в списках происходят только с одним элементом!
Ответ №1:
(==)
может использоваться только в контексте, который включает Eq
, но при объявлении count
вы не включили этот контекст. Если я правильно читаю, это было бы
count :: Eq a => Bag a -> a -> Integer
Если вы объявляете, count
не включая тип, вы можете запросить ghci
предполагаемый тип; или просто запросить предполагаемый тип snd (unwrap (filter (isObject Banana) [(Apple,1),(Banana,2)]))
Комментарии:
1. Ваше решение правильное, но я не совсем понимаю почему; Я предположил, что, поскольку функция isObject работает для сравнений, она не перестанет работать в этом контексте — что именно меняет добавление Eq a => в программе?
2.
Eq a
сообщает вашему компилятору, чтоtheObject
является членомEq
класса typeclass, а именно, что вы можете проверить, равен ли он чему-то еще того же типа. Существуют определенные типы данных (функции — лучший пример), которые не являются членамиEq
класса typeclass. (Например, ( 1) и (( 2).(-1)) невозможно проверить на равенство, хотя почти во всех случаях они вернут один и тот же результат.)3. Тайно функция класса типов, такая как
(==)
, просматривается в таблице, содержащей информацию о типе;Eq a =>
объявляет тип этой таблицы, который передается в качестве дополнительного аргумента за кулисами. (Если вы посмотрите на вывод ядра GHC, вы увидите, что фактические таблицы передаются по кругу.) С помощьюisObject
вы позволяете GHC самому определять тип, и он это сделал, включаяEq a
ограничение; но когда вы указываете типcount
самостоятельно, вы не можете оставить подобные вещи без внимания (по крайней мере, без некоторых довольно сложных правил). Все или ничего.4. Удаление явной подписи типа на
count
также устраняет проблему. Затем вы могли бы использовать ghci, чтобы увидеть, какой тип выводится.