> Can someone explain why you'd want uninhabited types?
Uninhabited types are useful for expressing units.
I'm writing an app that makes heavy use of a Haskell library[1] that implements currency units and exchange rates using uninhabited types (type-level strings).
So, one dollar will have the type `Amount "USD"`, whereas one Euro will have the type `Amount "EUR"` (both will have a value of `1`).
An exchange rate from Euros to dollars will have the type `ExchangeRate "EUR" "USD"` (the first type parameter being 'source' and the second 'destination'), and its value will be `1.14` (the current exchange rate from EUR to USD).
A function for converting an amount in one currency into another currency unit will take two arguments: `Amount src` and `ExchangeRate src dst` and return an `Amount dst`.
Also, in general, it can be useful to:
1. Remove an argument from a function
2. Create an uninhabited type that, at the type level, represents the values of this argument
3. Tag the function's return type with this uninhabited "phantom" type
because now you no longer have to remember from which argument some return value was calculated/derived: it's right there in the value's type.
[1] https://www.stackage.org/haddock/lts-12.6/safe-money-0.6/Mon...