In the land of Haskell Web Development, I tend to use newtypes instead of types. In works well in that domain because we often use the types opaquely anyway. For example, I might have a bunch of values like UserId, PageId, etc, which are really just an Int(eger) underneath. Preventing them from being mixed up is good. Also, I am not doing any calculations on them -- just storing, retrieving, and passing them around. Additionally, I am not usually creating the values directly in my code. That is, I don't have a bunch of code like, getUser (UserId 4). It is more like, do uid <- getUserId ; user <- getUser uid. So newtypes are great in this domain.
Outside of webdev, it is tempting to use type aliases for functions that have a lot of types where the meaning is not clear:
foo :: Int -> Int -> Double -> Double -> Double -> IO ()
using type alias provides a way to give them meaning:
foo :: X -> Y -> Red -> Blue -> Green -> IO ()
but, that is confusing because it hides the underlying types. It also duplicates information that is available in the function declaration.
foo :: Int -> Int -> Double -> Double -> Double -> IO ()
foo x y r g b = ...
Now we see types and description names. Except haddock does not include a way to show the names of the arguments in the docs.
Obviously, we need dependent types:
foo : (x : Int) -> (y : Int) -> (red : Double) -> (blue : Double) -> (green : Double) -> IO ()
And that will solve everything! What could possibly go wrong!
- jeremy