I would like to understand which is the difference between these two programming concepts. The first represents the absence of data type and at the latter the type exists but there is no information. Additionally, I recognize that Unit comes from functional programming theoretical foundation but I still cannot understand what is the usability of the unit primitive (e.g., in an F# program).
问题:
回答1:
The unit type just makes everything more regular. To an extent you can think of every function in F# as taking a single parameter and returning a single result. Functions that don't need any parameters actually take "unit" as a parameter, and functions that don't return any results return "unit" as a result. This has a variety of advantages; for one, consider how in C# you need both a slew of "Func" delegates to represent functions of various arities that return values, as well as a slew of "Action" delegates that do not return values (because e.g. Func<int,void>
is not legal - void cannot be used that way, since it's not quite a 'real' type).
See also F# function types: fun with tuples and currying
回答2:
In functional programming, we usually speak of mapping inputs to outputs. This literally means mapping an argument to its return value(s). But if something is going to be a function in the mathematical/category-theory sense, it has to return something. A void
value represents that a function returns nothing, which is nonsensical in these terms.
unit
is the functional answer to void
. It's essentially a type with only one value, ()
. It has a number of uses, but here's a simple one. Let's say you had something like this in a more traditional imperative language:
public static <T, U> List<U> map(List<T> in, Function<T, U> func) {
List<U> out = new ArrayList<U>(in.size());
for (T t : in) {
out.add(func.apply(t));
}
return out;
}
This applies a particular function func
to every element on the list, producing a new list of func
's output type. But what happens if you pass in a Function that just prints its arguments? It won't have an output type, so what can you put for U
?
In some languages, passing in such a function would break this code (like in C#, where you can't assign void
to a generic type). You'd have to resort to workarounds like having an Action<T>
, which can get clunky.
This is where the concept of unit
is useful: it is a type, but one that may only take on a single value. That greatly simplifies things like chaining and composition, and vastly reduces the number of special cases you have to worry about.