Я хочу создать свою собственную структуру данных списка под названием Nodes. Затем я буду использовать свой класс ListConverter, который содержит функцию 'toList', и создам его экземпляр.
data Nodes a = Empty
| Node a (Nodes a)
class ListConverter a where
toList :: a -> [Integer]
instance (Integral a) => ListConverter (Nodes a) where
toList Empty = []
toList (Node x Empty) = [x]
toList (Node x y) = x : toList y
GHCi говорит мне, что ожидаемый тип - «Integer», но в настоящее время «a». Я очень смущен, потому что в данном случае я даю тип для (Integral). Вот сообщение об ошибке:
error:
* Couldn't match expected type `Integer' with actual type `a'
`a' is a rigid type variable bound by
the instance declaration
at main.hs:7:10-48
* In the expression: x
In the expression: [x]
In an equation for `toList': toList (Node x Empty) = [x]
* Relevant bindings include
x :: a (bound at main.hs:9:18)
toList :: Nodes a -> [Integer] (bound at main.hs:8:5)
|
9 | toList (Node x Empty) = [x]
| ^
2 ответа
Ожидается, что ваш экземпляр ListConverter примет любое значение класса Integral для «a», но Integer - это определенный тип, а не класс; Вы должны сделать это:
instance ListConverter (Nodes Integer) where
Это или, наоборот, сделать ваш класс ListConverter способным создавать список любого типа, который содержит значение Nodes:
class ListConverter f where
toList :: f a -> [a]
instance ListConverter Nodes where
toList Empty = []
toList (Node x y) = x : toList y
(Второе уравнение для toList - (Node x Empty) - не нужно)
Проблема с этим экземпляром очень просто заявлена. Вы дали подпись:
toList :: a -> [Integer]
Но ваш попытанный экземпляр действительно имеет тип Nodes a -> [a]
. Это не работает, если a
не является типом Integer
- но вы утверждали, что это работает для всех Integral a
. Это включает в себя другие типы, такие как Int
.
Одним из решений является ограничение вашего экземпляра:
instance ListConverter (Nodes Integer) where...
Это сработает, но, на мой взгляд, не соответствует духу того, для чего вы, вероятно, предназначали класс.
Лучшее решение, которое я считаю, - это признать, что оба списка и ваш тип Nodes
параматизированы другим типом, и определить класс таким образом, чтобы выполнить преобразование по общему базовому классу. Это звучит сложнее, чем есть, я просто имею в виду:
class ListConverter l where
toList :: l a -> [a]
Затем вы можете написать instance ListConverter Nodes where...
и просто скопировать существующее определение toList
. (Чья средняя линия, я укажу мимоходом, является излишней.)
Новые вопросы
haskell
Haskell - это функциональный язык программирования, отличающийся строгой статической типизацией, отложенной оценкой, обширной поддержкой параллелизма и параллелизма и уникальными возможностями абстракции.