Создать пользовательскую структуру данных списка с помощью функции "toList" - PullRequest
0 голосов
/ 30 мая 2019

Я хочу создать свою собственную структуру данных списка с именем 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 ]

4 голосов
/ 30 мая 2019

Ваш экземпляр 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) - не нужно)

1 голос
/ 30 мая 2019

Проблема с этим экземпляром очень проста. Вы дали подпись:

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. (Чья средняя линия, я укажу мимоходом, является излишней.)

...