Как вы относитесь к типу "Либо 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)
? Какими должны быть определения функции-члена?