Происходит проверка: не может построить бесконечный тип?

Я пытаюсь написать функцию, которая для двух деревьев квадрантов, представляющих изображения, выводит другую логическую «маску» дерева квадрантов со значением True для пикселя, если оба дерева квадрантов имеют одинаковый цвет в соответствующей позиции, и False в противном случае.

Я получаю эту ошибку:

Occurs check: cannot construct the infinite type: a = QT a
  Expected type: QT (QT a)
  Inferred type: QT a
In the second argument of `mask', namely `c2'
In the first argument of `Q', namely `(mask a c2)'

и не могу понять почему. Функция:

data (Eq a, Show a) => QT a = C a | Q (QT a) (QT a) (QT a) (QT a)
    deriving (Eq, Show)

mask :: (Eq a, Show a) => QT a -> QT a -> QT Bool
mask q1 q2 = m q1 q2
    where
    m (C c1) (C c2) = C (c1 == c2)
    m (Q (C a) (C b) (C c) (C d)) (Q (C e) (C f) (C g) (C h))
        | and $ zipWith (==) [a, b, c, d] [e, f, g, h] = C True
        | otherwise = Q (mask a e) (mask b f) (mask c g) (mask d f)
    m (Q a b c d) (C c2)   = Q (mask a c2) (mask b c2) (mask c c2) (mask d c2)
    m c@(C _) q@(Q _ _ _ _) = mask q c
    m (Q a b c d) (Q e f g h) = Q (mask a e) (mask b f) (mask c g) (mask d h)

person gremo    schedule 06.02.2011    source источник


Ответы (2)


c2 имеет тип a, но маска требует аргумент типа QT a. Вы должны использовать шаблон @, как в строке ниже:

m (Q a b c d) c2@(C _)   = Q (mask a c2) (mask b c2) (mask c c2) (mask d c2)

Я думаю, что предыдущая строка также имеет ту же проблему.

person GS - Apologise to Monica    schedule 06.02.2011
comment
Таким образом, пытаясь унифицировать это, компилятор делает вывод, что тип a должен быть эквивалентен QT a, который работает только в том случае, если у вас есть QT (QT (QT....))) с бесконечной цепочкой оболочек QT. Вот что означает эта ошибка. - person Paul Johnson; 06.02.2011

Вы не совсем это спросили, но... эта строка:

m (Q (C a) (C b) (C c) (C d)) (Q (C e) (C f) (C g) (C h))

Это просто...

Много лет назад мы с другом научились программировать на Бейсике. Он создал очень крутую игру про космические корабли. Я сказал ему, что он должен добавить больше космических кораблей, и это будет круче. Он сказал, что это была тяжелая работа. Оказывается, он не знал о массивах и дублировал код для каждого из 8 кораблей на экране.

Пожалуйста, сделайте код чище, примерно так:

data SplitTree a = Leaf a | SplitNode [SplitTree a]
  deriving (Eq, Show)

mask :: Eq a => SplitTree a -> SplitTree a -> SplitTree Bool
mask (Leaf x) (Leaf y) = Leaf (x == y)
mask (SplitNode xs) (SplitNode ys)
  | and $ zipWith (==) xs ys = Leaf False
  | otherwise = SplitNode $ zipWith mask xs xs

(Я не уверен на 100 %, что вы пытались это сделать, но я мог или не мог намеренно внести в этот код несколько простых ошибок, так как не люблю делать домашнюю работу)

Написание хорошего кода облегчает его исправление. Если не правильно, то баги найти проще.

Трудно помочь вам с этим беспорядком. Самый простой способ исправить такое безобразие — переписать. Разве это не пустая трата времени?

Прежде чем приступить к решению небольшой проблемы, связанной с тем, что ваш код не работает, пожалуйста, решите большую проблему, связанную с беспорядком. Мне и другим пришлось много страдать, поддерживая неподдерживаемый код, пожалуйста, постарайтесь сделать хороший код.

person yairchu    schedule 06.02.2011
comment
если дерево квадрантов Гремо имеет ровно четыре элемента для ветви, то использование конструктора с четырьмя сортировками намного лучше, чем превращение его в дерево роз (в конце концов, оно называется деревом квадрантов...). Представление списка плохо для эффективности и плохо для правильности. - person stephen tetley; 06.02.2011
comment
@stephen tetley: Если вы настаиваете на использовании четырехъядерных деревьев с принудительным типом, вы все равно можете создать две вспомогательные функции для деконструкции и построения фиксированных четырех элементов в списки. - person yairchu; 06.02.2011