In algebra functions are a way to map from one set of objects (the domain) to another set of objects (the codomain). In traditional imperative programs functions are a way to sequence operations to achieve a desired state. In some sense traditional imperative programs encourage reasoning about implementation details. Instead if we think about our functions in the same sense as in algebra, as mappings from some set to another, the implementation becomes almost incidental. Traditional imperative programming doesn't encourage this sort of thinking. It's a style of thinking that encourages reasoning about behavior over implementation. While there can be differences between implementations of the same function, the differences between implementations are almost always performance related and do not alter the domain and codomain.
Knowing the domain and codomain gives us information about how a function behaves in isolation. It clearly identifies potential edge cases, usually the first and last elements in an ordered set. Perhaps most importantly, it allows us to reason about how it will behave when combined with other functions. If we were composing functions f and g: f * g, the codomain of g must be a subset of the domain of f. If it is not a subset, then the behavior of this composition cannot be defined for all possible inputs.