Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Haskell's algebraic data types: "pseudo-extend"

I am learning about Algebraic DTs in haskell. What I would like to do is create a new ADT that kind of "extends" an existing one. I cannot find how to express what I would like, can someone sugest an alternative pattern or sugest a solution. I want them to be distinct types, but copying and pasting just seams like a silly solution. The code below best describes what I am seeking.

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)

Edit: I think It need a little clarification... I want to be able to do this (in ghci)

let a = Abkhazia :: Country

and not

let a = Power Abkhazia :: Country
like image 256
Ra is dead Avatar asked Jun 17 '12 18:06

Ra is dead


2 Answers

You need to represent them as a tree:

  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)

Edit: your extension to the question makes this a bit simpler: both the Country and Power types share some common behavior as "countries". This suggests you use the open, extensible type class feature of Haskell to given common behaviors to the data type. E.g.

  data Power = Abkhazia | Transistria 

  data Countries = Neutral | Water

then, a type class for things both Power and Countries share:

  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

then you can use landarea cleanly on either powers or countries. And you can extend it to new types in the future by adding more instances.

like image 93
Don Stewart Avatar answered Nov 12 '22 18:11

Don Stewart


{-# 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

Edit: An alternative would be type Power = forall a. CountryLike a (Advantage: Makes Power a subtype of Country. Disadvantage: This would make e.g. Power -> Int a higher-rank type, which tend to be annoying (type inference etc.))

like image 33
FunctorSalad Avatar answered Nov 12 '22 16:11

FunctorSalad