Not directly. The problem is that characters are a built-in type that does not have the ability to polymorphism. This is different from numeric literals that are designed for polymorphism using a class of type Num .
However, there are two main approaches you can take: a newtype shell with an intelligent constructor or a completely new type.
The newtype wrapper is easier to use:
module Vowel (Vowel, vowel, fromVowel) where newtype Vowel = Vowel Char vowel :: Char -> Maybe (Vowel) vowel x | x `elem` "aeiouAEIOU" = Just (Vowel x) | otherwise = Nothing fromVowel :: Vowel -> Char fromVowel (Vowel x) = x
Since the Vowel constructor is not exported, the new Vowel can only be created with the Vowel function, which only accepts the characters you want.
You can also create a new type:
data Vowel = A | E | I | O | U | Aa | Ee | Ii | Oo | Uu fromChar :: Char -> Maybe Vowel fromChar 'a' = Just Aa fromChar 'A' = Just A -- etc. toChar :: Vowel -> Char toChar Aa = 'a' toChar A = 'A'
This second method is rather difficult and therefore much more inconvenient to use.
So how to do it. I'm not quite sure what you want, though. The usual idiom is to create types that represent your data, and you specifically do not represent vowels. A typical template would look something like this:
newtype CleanString = Cleaned { raw :: String } -- user input needs to be sanitized cleanString :: String -> CleanString
Here, a new type distinguishes between unauthorized and disinfected entry. If the only way to make CleanString on CleanString , then you know statically that every CleanString is sanitized correctly (assuming CleanString correct). In your case, it seems that you really need a type for consonants, not vowels.
Haskell's Newtypes are very lightweight *, but the programmer has to write and use the code to wrap and deploy. In many cases, the benefits outweigh the extra work. However, I really can't come up with any application where it is important to know that your String is a vowel, so I probably just work with a simple String .
* newtypes exist only at compile time, so theoretically there is no need to use them at run time. However, their existence can change the generated code (for example, prohibit RULES), so sometimes a measurable impact on performance is observed.