Как вы относитесь к типу "Либо b"?

Цель этой конкретной части кода - сделать функцию size более эффективной, чем просто подсчет всех элементов в elems. Я остановился на суммировании двух типов, составляющих список, но я не могу создать подпись функции размера.

instance (Finite a, Finite b) => Finite (Either a b) where
    elems = combineLists [Left x | x <- elems] [Right x | x <-elems]
    size ??? = (size a) + (size b)

Из Prelude мы знаем, что Either a b = Left a | Right b.

Первое, что я пробовал, это совпадение Either, но, конечно, это тип, так что это не работает. Затем я попробовал ((Left a) | (Right b)), но так и не пошел. Ничто иное не похоже на тип Either a b.

Мне удалось получить size (Left a) для компиляции, но поскольку он не имеет компонента b, я получаю сообщение об ошибке:

Ambiguous type variable `b' in the constraint:
  `Finite b' arising from a use of `size' at <interactive>:1:0-12

что, конечно, имеет смысл в контексте, но я действительно не знаю, как сопоставить Either a b.

У кого-нибудь есть мысли?

Ответ 1

Что-то типа Either a b является либо Left a, либо Right b, поэтому у вас есть два случая, которые можно обрабатывать отдельно:

size (Left x) = size x
size (Right x) = size x

Ошибка в переменной неоднозначного типа является отдельной проблемой. Если вы просто введете что-то вроде size (Left 1) в интерпретатор, система не сможет определить, что такое "правильный" тип этого значения Left 1. Это может быть Either Int anything, и пока неизвестно, какой тип anything, он не может быть проверен, если он находится в классе Finite (который требуется size).

Вы можете избежать этой проблемы, указав явную подпись типа:

size (Left 1 :: Either Int String)

Ответ 2

Проблема состоит в том, что вам нужен фиктивный аргумент для size, но вы не можете передавать макеты для обоих типов a и b в одном Either a b. Возможно, вы можете использовать elems, чтобы получить фикцию каждого типа:

size _ = (size . head) (elems :: [a]) + (size . head) (elems :: [b])

Ответ 3

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

Простой тип данных, который одновременно представляет собой как a, так и b, представляет собой 2-кортеж. Типичная подпись для такой вещи - (a, b), которая также является выражением для ее создания и, следовательно, шаблоном:

> :type (4,5)
(4,5) :: (Num t, Num t1) => (t, t1)
> let f (a, b) = 2*a + b
> f (4,5)
13

Вам следует рассмотреть возможность написания первой строки с помощью 2-х кортежей, например:

 instance (Finite a, Finite b) => Finite (a, b) where

Что это означает Finite (a, b)? Какими должны быть определения функции-члена?