Search code examples
haskelltype-safetytype-aliasnewtype

Is it bad form to make new types/datas for clarity?


I would like to know if it is bad form to do something like this:

data Alignment = LeftAl | CenterAl | RightAl
type Delimiter = Char
type Width     = Int

setW :: Width -> Alignment -> Delimiter -> String -> String

Rather than something like this:

setW :: Int -> Char -> Char -> String -> String

I do know that remaking those types effectively does nothing but take up a few lines in exchange for clearer code. However, if I use the type Delimiter for multiple functions, this would be much clearer to someone importing this module, or reading the code later.

I am relatively new to Haskell so I do not know what is good practice for this type of stuff. If this is not a good idea, or there is something that would improve clarity that is preferred, what would that be?


Solution

  • You're using type aliases, they only slightly help with code readability. However, it's better to use newtype instead of type for better type-safety. Like this:

    data Alignment = LeftAl | CenterAl | RightAl
    newtype Delimiter = Delimiter { unDelimiter :: Char }
    newtype Width     = Width { unWidth :: Int }
    
    setW :: Width -> Alignment -> Delimiter -> String -> String
    

    You will deal with extra wrapping and unwrapping of newtype. But the code will be more robust against further refactorings. This style guide suggests to use type only for specializing polymorphic types.