#haskell
#haskell
Вопрос:
Я не могу понять, почему, хотя я объявил типы данных, функция не принимает разные возвращаемые значения. Я также пытался создать тип «Результат», но этого было недостаточно для решения проблемы.
Взгляните на мой код:
type Set a = [a]
type Bag a = [(a, Int)]
type Seq a = [a]
data ComposedType a = Set a | Bag [a] | Seq a deriving(Eq, Show)
data ComposedResult a = Res1 [a] | Res2 [(a, Int)]
-- This function get a list [a] and returns a list of tuples [(a, Int)]
occrs :: (Ord a) => [a] -> [(a, Int)]
occrs [] = []
occrs xs = toList (fromListWith ( ) [(x, 1) | x <- xs])
--getElements :: ComposedType a -> ComposedResult a
getElements (Set a) = (Set (nub a))
getElements (Seq a) = (Seq (sort a))
getElements (Bag a) = (Bag (occrs a))
Ошибка:
- Не удалось сопоставить type ([a], Int) с ‘[a]’ Ожидаемый тип: ComposedType [a] Фактический тип: ComposedType ([a], Int)
- В выражении: (Bag (occrs a)) В уравнении для ‘getElements’: getElements (Bag a) = (Bag (occrs a))
Комментарии:
1. Обратите внимание, что
set
используетa
, так что это означает, что в первой строке нуженComposeType [a]
, а неComposeType a
., то же самое сseq
. Но теперьBag
потребностиb ~ (a, Int)
, отсюда и ошибка.2. Вы используете
Set
как псевдоним типа, так и имя конструктора. Эти два использования не связаны: определение типаdata ComposedType a = Set a | Bag [a] | Seq a
вообще не использует типSet a
. То же самое дляBag
иSeq
. Вероятно, это не то, что вы хотели.3. Вы верите
Set
, что intype Set a = [a]
иSet
indata ComposedType a = Set a | ...
связаны друг с другом? Если это так, это может быть основной причиной вашей путаницы — это одно и то же имя, но в двух разных пространствах имен (пространство имен типов для первого и пространство имен вычислений для последнего) — и, возможно, стоит добавить ответ, в котором обсуждается это.
Ответ №1:
Причина, по которой это не работает, заключается Set (num a)
в том, что, например, имеет тип ComposedType [a]
, тогда как для Bag (occrs)
, это потребует ComposedTYpe (a, Int)
, поскольку Bag
использует, в отличие от других конструкторов данных, список a
s: [a]
.
Если вы используете a ComposedResult
, то вам нужно будет использовать Res1
Res2
конструкторы данных и:
getElements :: (Eq a, Ord a) => ComposedType [a] -> ComposedResult a
getElements (Set b) = Res1 (nub b)
getElements (Seq b) = Res1 (sort b)
getElements (Bag b) = Res2 (occrs b)
но это все равно не сработает. Действительно Bag a
, имеет параметр b
, но b
имеет тип as [[a]]
, и хотя occrs
может работать со списком списков (поскольку они также являются экземпляром Ord
if элемент является экземпляром ord
, это будет означать, что occrs b
он имеет тип [([a], Int)]
, тогда как другие ( nub b
и sort b
) имеют тип [a]
, так что это снова вызовет проблемы.
Мы можем исправить это, объединив, например, элементы b
вместе:
getElements :: (Eq a, Ord a) => ComposedType [a] -> ComposedResult a
getElements (Set b) = Res1 (nub b)
getElements (Seq b) = Res1 (sort b)
getElements (Bag bs) = Res2 (occrs (concat bs))
но, вероятно, вы допустили ошибку, указав [a]
в качестве параметра для bag , таким образом, вы можете исправить тип и использовать:
data ComposedType a = Set a | Bag a | Seq a deriving (Eq, Show)
getElements :: (Eq a, Ord a) => ComposedType [a] -> ComposedResult a
getElements (Set b) = Res1 (nub b)
getElements (Seq b) = Res1 (sort b)
getElements (Bag b) = Res2 (occrs b)
Комментарии:
1. Я думаю, вам не хватает большой проблемы:
ComposedType
он вообще не используетSet
псевдонимы,Bag
, илиSeq
типа: он просто содержит одинa
, украшенный одним из 3 конструкторов, имена которых совпадают с этими типами. Энрике Н. Мендес, вероятно, предполагал, что вместо этого он фактически содержит Set , Bag или Seq .