Как возвращать разные типы в одной и той же функции в haskell?

#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 , что in type Set a = [a] и Set in data 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 .