`f x y = 5`

is a 2-argument function, and `f x = 5`

is a 1-argument function, I thought `f = 5`

must be a 0-argument function. The syntax makes it hard to tell that all functions take exactly one argument.
]]>However, the viewpoint “everything can be seen a function (in addition to whatever else it is)” seems quite reasonable. As others have pointed out, n-ary (curried) functions are a very helpful concept, where formally an n-ary function can be defined as a term of type “A_1 -> … -> A_n -> B”, for some types A_1 … A…n. So “map” can be seen both as a unary function from “A -> B” to “[A] -> [B]”, and also as a binary function from “A -> B” and “[A]” to “[B]”.

But then by the same token, the integer 5 is a nullary function to “Int”; it’s also still an “Int”, but that doesn’t stop it being a nullary function as well.

So “everything is an n-ary function, for some n” is surely acceptable? In the context of Haskell, I don’t know how useful it is; but in some mathematical contexts, it’s very fruitful indeed (e.g. the insight that constants could be seen as 0-ary functions was essential for universal algebra, and its cousin the theory of operads).

]]>Let X and Y be sets and let the cartesian product of X and Y, denoted X x Y be the set {(x,y) | x belongs to X, y belongs to Y}. A function from X to Y, written as f : X -> Y, is a subset of X x Y with the property that for all (x1,y1), (x2,y2) in f, x1 = x2 implies that y1 = y2.

This is the mathematical definition of of a function and is the one used by Haskell and probably the other functional programming languages as well. The defining property of the function as stated above is usually referred to as ‘referential transparency’. The C programming language started the confusion, and other such languages have perpetuated it, by using the term function to mean something quite different. In C a function is not necessarily an association at all – it may not take an input and it may not produce an output – it may be pure side effect and even if it does define an association there is no guarantee of referential transparency.

Adopting this definition, how do you make sense of the phrase ‘a function with 0 arguments’?

]]>`undefined`

example is tricky.
In general, we might say that “`foo`

is a function” exactly if `foo`

has function type, i.e., `foo :: a -> b`

for some types `a`

and `b`

.
In that case, `undefined`

passes the test, since `undefined :: a -> b`

not only for some types but for `a`

and `b`

.
Of course by this same line of thought, `undefined`

“is a” number, list, pair, boolean, etc.
However, I’m guessing that the section you quoted about `error`

and `undefined`

was simply careless writing.
I see what you mean about “nullary constructor” reinforcing the idea of “everything is a function in Haskell”.

As for a single-word expression, we do have “identifier”.
But it wouldn’t work very well in your example: “The Prelude provides two identifiers to directly cause such errors: …”.
Identifiers themselves cannot cause errors.
It’s really the values *bound* to these two identifiers.
Here are some other attempts and criticisms:

- “The Prelude defines two identifiers to directly cause such errors: …”. Vague relationship between identifiers and causality.
- “The Prelude defines two values to directly cause such errors: …”. Values cannot be defined. Only names.
- “The Prelude provides two definitions for directly causing such errors: …”. Again, definitions do not cause anything.
- “The Prelude names two values that directly cause such errors: …”. Most accurate in my comprehension.

I hadn’t realized that the Haskell report itself was encouraging the sort of confusion I keep noticing. Thanks for pointing out these statements. Now I wonder whether we’ve even developed careful enough language to say what we mean here.

As Bertrand Russell said, “Everything is vague to a degree you do not realize till you have tried to make it precise.”

]]>It seems that the Haskell Report distinguishes data constructors from functions, but yet they are generally indistinguishable aside from deconstruction in pattern matching, e.g. if I type (“:t (:)”) it appears to be a normal function. Yet section 3.6 of the report mentions “where True and False are the two nullary constructors from the type Bool”, which makes it sound like data constructors can be thought of as functions, and ones with no arguments are just nullary functions.

Maybe the source of the problem is that AFAICT there’s no good word to refer to “a single-word expression, either a variable, function, operator, or data constructor”. In most contexts, those things all act the same. To say “value” isn’t really correct, as that refers to the underlying result of an evaluation. To say “expression” doesn’t make it clear that we’re talking about a single word.

]]>… In the class I took, everything is a set: functions, numbers, tuples, lists, etc. So I don’t think it is unreasonable to make things out of lists or tuples. …

Trinithis: I’m very sympathetic to your perspective here. And I understand it to be in the category I called “Interested in a different conversation” above:

This one was the hardest of all for me to get so far and was a real lightbulb moment for some people’s belief that everything is a function in Haskell. They don’t believe it. They’d rather talk about something else, such as formalisms in which everything is a function. Or maybe they even have a different notion of what topic is being discussed.

Which is not at all to say that the alternative topic is any less important than the original one.

]]>As for 7 being a function, I think it could work using similar thinking. Whether or not such thinking gets you anywhere is up to debate though.

]]>So this may be another source for this.

]]>