This strikes me as having some interesting similarity to the practice in Haskell of placing type class constraints on functions, not data types. A deprecated feature of Haskell used to allow you to write data types like: data Ord k => Map k v = ...
This defined a data type representing an ordered map from k to v, with the additional restriction that before you can talk about such a map you had to know that the type k is orderable (has an instance of the Ord type class which defines comparison operators).This may be considered to be similar to the definition of (/) requiring that its second argument is nonzero. This style was supplanted by leaving the data type definition 'bare' and placing the constraints on the API's functions instead: data Map k v = ...
insert :: Ord k => k -> v -> Map k v -> Map k v
lookup :: Ord k => k -> Map k v -> Maybe v
This style is similar to instead placing the nonzero-ness constraint on the theorems which define the API of (/).In both cases there are basic engineering reasons for the switch: - Having the constraints in the definition of terminology (Map, /) doesn't save any work, as you still need to prove those constraints to do anything or refer to it (in Haskell this meant sprinkling `Ord k =>` in the type of anything that referred to Map k v). - In fact it results in doing more work than necessary, as you are sometimes forced to prove the constraints just to mention Map, even when what you are doing does not require them. For instance defining the empty map 'empty :: Map k v' shouldn't require you to know anything about k, because an empty tree doesn't contain any keys, let alone care about their ordering. In this case requiring Ord k in order to mention Map k v would be superfluous. |
(This is by no means a standard across the community though; I'd say it's a 50/50 split)