Search code examples
haskelltypestype-safetyalgebraic-data-typestype-alias

What's the right way to use type aliases in Haskell


I'm a total beginner with Haskell. While trying to solve some practice exercises on hackerrank I stumbled over an error, which made me wonder about doing it "the right way"(tm).

What I was trying to do was this:

import Data.Matrix

newtype Puzzle = Matrix Char

complete :: Puzzle -> Bool
complete p = '-' `elem` (toList p)

[... more functions on 'Matrix Char']

and this gave me:

Couldn't match expected type ‘Matrix Char’
                with actual type ‘Puzzle’
    In the first argument of ‘toList’, namely ‘p’
    In the second argument of ‘elem’, namely ‘(toList p)’

The obvious solution is of course just using Matrix Char instead of Puzzle. But I don't feel that this is an elegant solution. An abstraction into a more specific type feels like the right way to go...


Solution

  • I think a better solution than the one offered by Jeffrey's answer, at least in the case of more substantial code bases than a toy game, is to keep using newtype but to change the code to this:

    import Data.Matrix
    
    newtype Puzzle = Puzzle (Matrix Char)
    
    complete :: Puzzle -> Bool
    complete (Puzzle matrix) = '-' `elem` toList matrix
    

    This will allow you to keep using a truly distinct data type as opposed to resorting to a type alias, which doesn't introduce any new types and will allow completely interchangeable use of Puzzle and Matrix Char with no added type safety (nor expressiveness).

    Also, Jeffrey is right in that newtype is more similar to data than typenewtype offers some performance optimisations over data but is more restricted and slightly affects the program evaluation semantics. You're better off reading up on all the various ways of defining types and type aliases in Haskell.

    In your case, you might as well substitute data for newtype without changing the behavior of your program; the rest of the program should continue to work identically.

    See also: Haskell type vs. newtype with respect to type safety