Алгебраические типы данных Haskell: псевдорасширение

Я изучаю алгебраические DT в haskell. Что я хотел бы сделать, так это создать новый ADT, который как бы «расширяет» существующий. Я не могу найти, как выразить то, что я хотел бы, может ли кто-нибудь предложить альтернативный шаблон или предложить решение. Я хочу, чтобы они были разными типами, но копирование и вставка только швов кажется глупым решением. Код ниже лучше всего описывает то, что я ищу.

data Power =
  Abkhazia |
  -- A whole bunch of World powers and semi-powers
  Transnistria
    deriving (Eq, Show)

data Country = 
  --Everything in Power | 
  Netural |
  Water
    deriving (Eq, Show)

Изменить: я думаю, что нужно небольшое пояснение... Я хочу иметь возможность сделать это (в ghci)

let a = Abkhazia :: Country

и не

let a = Power Abkhazia :: Country

person Ra is dead    schedule 17.06.2012    source источник
comment
Причины, по которым это нужно сделать, обычно исходят из ОО-школы мысли ;-), но вы всегда можете добавить конструктор в Country для PowerCountry, держащей Power.   -  person Kristopher Micinski    schedule 17.06.2012
comment
Хм, могу я спросить, как Абхазия и Приднестровье попали в кусок кода Haskell? Как вы связаны с этими двумя местами? Вы работаете над какой-то игрой? Из какой ты страны?   -  person Cetin Sert    schedule 17.06.2012
comment
Абхазия и Приднестровье являются первыми и последними в списке Других государств на en.wikipedia.org/wiki/List_of_sovereign_states Я только изучаю Haskell и придумал кое-что для практики. Я предполагаю, что это может быть игра, но у меня пока нет никаких намерений.   -  person Ra is dead    schedule 18.06.2012


Ответы (2)


Вам нужно представить их в виде дерева:

  data Power
      = Abkhazia
      | Transnistria
    deriving (Eq, Show)

  data Country 
      = Powers Power -- holds values of type `Power`
      | Netural      -- extended with other values.
      | Water
    deriving (Eq, Show)

Изменить: ваше расширение вопроса делает это немного проще: и типы Country, и Power имеют общее поведение как «страны». Это предполагает, что вы используете открытую, расширяемую функцию класса типов в Haskell, чтобы задать общее поведение для типов данных. Например.

  data Power = Abkhazia | Transistria 

  data Countries = Neutral | Water

затем класс типов для вещей, которые разделяют Power и Country:

  class Countrylike a where
      landarea :: a -> Int -- and other things country-like entities share

  instance Countrylike Power where
      landarea Abkhazia    = 10
      landarea Transistria = 20

  instance Countrylike Countries where
      landarea Neutral     = 50
      landarea Water       = 0

тогда вы можете использовать landarea как для держав, так и для стран. И вы можете расширить его до новых типов в будущем, добавив больше экземпляров.

person Don Stewart    schedule 17.06.2012
comment
Это почти то, что я хочу, но посмотрите на разъяснение. Спасибо! - person Ra is dead; 17.06.2012
comment
@Raisdead, вы не можете сделать это в Haskell, и Дон знал бы, ... (Однако вы можете использовать классы типов с несколькими параметрами для имитации подтипов, что может быть тем, что вы имеете в виду. В любом случае, Ответ Дона, вероятно, лучший, который вы получите, и то, что вы должны использовать.) - person Kristopher Micinski; 17.06.2012

{-# LANGUAGE GADTs, StandaloneDeriving #-}
data POWER
data COUNTRY

data CountryLike a where
    Abkhazia :: CountryLike a 
    Transnistria :: CountryLike a
    Netural :: CountryLike COUNTRY
    Water :: CountryLike COUNTRY

deriving instance Show (CountryLike a)
deriving instance Eq (CountryLike a)

type Power      = CountryLike POWER
type Country    = CountryLike COUNTRY

foo :: Power
foo = Abkhazia

bar :: Country
bar = Abkhazia

baz :: Country
baz = Netural

Редактировать: альтернативой может быть type Power = forall a. CountryLike a (Преимущество: делает Power подтипом Country. Недостаток: это сделает, например, Power -> Int типом более высокого ранга, который, как правило, раздражает (вывод типа и т. д.))

person FunctorSalad    schedule 17.06.2012