KenavR
KenavR

Reputation: 3899

"SubTypes" with own Show and usable in other Module

I am pretty sure my problem stems from the fact that I am new to Haskell and do not understand the type system completely.

I will use the example used in Haskell's wiki on the type topic

The following Type is defined

 data Suit = Club | Diamond | Heart | Spade

Now the first issue is, I would like to implement Show for every "sub-type" (Club, Diamond, Heart, Spade) but this doesn't seem to work because it is a DataKinds. So I split it up into their own types. (The properties don't make much sense but I added them to be closer to the real code)

data ClubType = ClubType {
  clubName :: String,
  icon :: String
} 
instance Show ClubType where
  show (ClubType cn i) = "name: " ++ cn ++ ", icon: " ++ i

Using them in the Suit type

data Suit = Club ClubType 
          | Diamond DiamondType 
          | Heart HeartType 
          | Spade SpadeType

Now I want to use Suit and the "Sub-Types" (Club, Diamond, Heart, Spade) in a different module. I exported just Suit (..).

Usage

import Module1 (Suit(..))

getSuit :: String -> Suit
getSuit "Club" = getClub
getSuit "Heart" = getHeart
...

getClub :: () -> Club

Now again Club, Heart, Diamond and Spade cannot be used because they are DataKinds. How do I use the "sub-types"? Do I need to export all types? If I do, does it conform with the return type of getSuit?

(Sorry if the example doesn't make a whole lot of sense, but I hope you can follow my desired result)

thanks

Upvotes: 1

Views: 65

Answers (1)

luqui
luqui

Reputation: 60503

Yes it sounds like you don't really understand the type system. I will try my best to clarify where I think you are going wrong. In your example

data Suit = Club | Diamond | Heart | Spade

There is only one type, and that is Suit. Club, Diamond, etc. are not types at all, and you will confuse yourself if you refer to them as "sub-types". The proper name for them is constructors, and they are essentially values of type Suit

Club :: Suit
Diamond :: Suit
...

So you can't really implement a Show instance for "each one", you can only implement a Show instance for the whole type Suit, in the usual way, by pattern matching on the constructors:

instance Show Suit where
    show Club = "Clubs"
    show Diamond = "Diamonds"
    show Heart = "Heart"
    show Spade = "Spade"

This defines a single function show on the type Suit -> String, again there is no "sub-type" anything going on. I wonder if this was all you were looking for.

Since you mention datakinds, using the constructors at the type level still does not make them types -- they are still values of type Suit. An example of using them at the type level is to index a GADT by these:

data Card :: Suit -> * where
    QueenOfSpades :: Card Spade
    OtherCard :: Int -> Card s   -- we'd want to encode the suit s at the data
                                 -- level too using a singleton, out of scope
                                 -- for this post

But this is fairly advanced stuff and probably not what you are looking for.

I hope this clarifies things a little.

Upvotes: 5

Related Questions