7
$\begingroup$

Sorry if I am not using the correct terminology here, I'll correct it if it turns out to be that way.

Programming languages such as Python or Mathematica typically have function syntax implemented as f(a,b), f[a,b] or something similar to that (of course for example when dealing with functions having more than one input).

However, with languages like Uiua, functions are usually implemented as f a b, for example this code which outputs the argument of a complex number $\arg(z)$ (in this case $\arg(2+i)$):

F ← ׯi ₙe±ℂ∩
F 1 2

My question is, why implement it this way? Are there any benefits to doing it like so?

$\endgroup$
12
  • 6
    $\begingroup$ See currying. $\endgroup$ Commented Apr 16 at 22:32
  • 7
    $\begingroup$ You don't need to reach for esoteric languages to find examples of this ─ most mainstream functional programming languages use this syntax for function application, and it's also common in shell languages to invoke commands with no parentheses around their arguments. See here for a partial list. $\endgroup$
    – kaya3
    Commented Apr 16 at 23:21
  • 4
    $\begingroup$ Stack-based languages like Uiua or Forth have a completely different motivation and underlying mechanism for this than functional languages. $\endgroup$ Commented Apr 17 at 12:58
  • 3
    $\begingroup$ @UnrelatedString Which is...? $\endgroup$
    – Pablo H
    Commented Apr 17 at 14:03
  • 3
    $\begingroup$ It's probably a legacy of Fortran. In Fortran, whitespace is insignificant, so you need some other punctuation to separate the function name from the arguments, and the arguments from each other. Parentheses and commas were natural choices. $\endgroup$
    – Barmar
    Commented Apr 17 at 22:35

2 Answers 2

9
$\begingroup$

For f a b to represent a function call, you need some way to decide if it's f(a, b) or f(a(b)) or some other nesting. Some types of language have definitions or equivalents of function that give a natural answer to that, and use this to optimise syntax for a common case.


Polish Notation, eliminates the need for operator precedence rules if every function and operator has a fixed arity (number of operands or formal parameters). Stack-oriented languages such as Forth generally use Reverse Polish Notation, where values are placed on the stack as the program is read left to right, and an operator or function takes a fixed number of items from the stack, and places its result in their place.

In Reverse Polish Notation, b a f means "put b and a on the stack, then run sub-routine f, which will take two arguments off the stack". In more common parenthesis style, that's equivalent to f(a, b) - "run sub-routine f with arguments a and b".

Note that this makes nested function calls implicit, and thus concise: if f and a are both functions that require one input, b a f instead represents "apply function a to argument b, then apply function f to the result" - or in parenthesis style, f(a(b)).

Uiua, mentioned in the question, is described as "stack-based but not stack-oriented", and processes each line of input from right to left. I haven't look at the details, but this is roughly Polish Notation (without the "Reverse").

In this case f a b is equivalent to "run sub-routine f with arguments b and a", i.e. parenthesis-style f(b, a) or f(a, b). Nesting is again implicit: if a is actually a function, f a b will instead mean "apply function a to argument b, then apply function f to the result" - or in parenthesis style, f(a(b)).


Functional programming languages such as Haskell make heavy use of currying, where a function with multiple parameters is decomposed into a series of single-parameter functions which "partially apply" the full operation. The syntax then treats applying a function to one operand as the default operation.

This makes it possible to read f a b as a series of applications from left to right: call function f with the single argument a, then call the resulting function with single argument b. In parenthesis style, that would be f(a)(b).

Passing functions themselves as parameters to "higher-order functions" is not just allowed but common, so the above rule applies even if a is itself a function. If you wanted to apply function a, rather than passing it as an argument to f, you would use parentheses to change the precedence: f (a b) would be equivalent to parenthesis-style f( a(b) ).


In command-based languages, such as shell scripting, most statements consist of a single command (equivalent to a function) and its arguments. Evaluating a command within a larger expression is treated as the exception, rather than the rule, so has to be specified explicitly

For example, f a b means "run command f with literal arguments 'a' and 'b'", equivalent to parenthesis-style f('a', 'b'). In many Unix shells, you can write f $(a b) for "run command a with literal argument 'b'; then run command f with that result as its argument" - equivalent to f(a('b')).

Assembly languages are generally an extreme form of this, where statements always consist of a single operation and a fixed list of operands.


Finally, in Lisp and its descendents, functions are executed by evaluating the first item of a list as a function name, and the remainder as the list for it to process. This "homoiconicity" (unification of source code and data) makes it easy to write powerful meta-programming facilities by manipulating lists of symbols before executing them.

So (f a b) will be interpreted as "execute function f with argument list (a b)"; the equivalent in parenthesis notation would be f(a, b).

Unlike in Polish notation, nesting is explicit: to represent "apply function a to argument b, then apply function f to the result", you have to write (f (a b)). This leads to the frequently discussed fact that Lisp programs generally require more parentheses than those in other languages.

$\endgroup$
8
  • $\begingroup$ Haskell makes heavy use of infix operators as well -- prefix is only used for unary operators. $\endgroup$
    – Chris Dodd
    Commented Apr 21 at 21:44
  • $\begingroup$ @ChrisDodd Fair point. Apparently, infix operators can be used as prefix functions, and vice versa, so the whole program could be written in either style. I'm not sure where that leaves the logic of my answer. $\endgroup$
    – IMSoP
    Commented Apr 21 at 22:09
  • $\begingroup$ @ChrisDodd Thinking about it, I don't think Polish notation is particularly relevant to the Haskell example, so I've restructured my answer to not connect the two. $\endgroup$
    – IMSoP
    Commented Apr 22 at 3:15
  • 1
    $\begingroup$ @IMSoP I might be missing something here but the answer seems to barely discuss syntax and especially the why of it. For example, the Functional programming languages paragraph mostly explains currying, and how parentheses can be used given the Haskell syntax - but it does not say why the syntax was chosen that way. There's a bit that can be inferred here - that the syntax is useful with currying - but that isn't spelled out. Likewise, that f (a b) isn't "the mathematical f(a,b)" is shown but not pointed out; [...] $\endgroup$ Commented Apr 22 at 8:11
  • 1
    $\begingroup$ @MisterMiyagi I've added a bunch more details - possibly too much, to be honest, but I didn't have time to write a shorter letter. Does that cover what you felt was missing? (I always find "why" questions difficult - ultimately, the answer to "why does Haskell look that way?" is "because the people who designed it made it look that way"). $\endgroup$
    – IMSoP
    Commented Apr 22 at 10:30
0
$\begingroup$

Programming languages use simple juxtaposition (f a) for function application because it is the standard notation for function application that has been used for more than 100 years, before the first electronic computers or high-level programming languages existed.

When there are mulitple arguments or other expressions involved, you would need parentheses to disambiguate. For example, one would use f(a + b) to apply f to the result of a+b, while f a + b would instead apply f to a and then add b to the result. So the real question is "why did languages start requiring parentheses for function application even when they are not needed for precedence/disambiguation?"

This originated with FORTRAN, which had two features that interact to require the parentheses:

  • Multi-character names are allowed for things, so something like fab would be a single symbol, and not series of symbols involving some function applications
  • Whitespace is completely insignificant and ignored, so f a b and fab are the same.

This was then carried over into later languages, even when they made whitespace significant.

$\endgroup$
7
  • 5
    $\begingroup$ The current top answer to this related question asserts exactly the opposite of your first paragraph: that f(x) is the most common mathematical notation. That certainly matches my (non-expert) experience: f x represents multiplication, not function application. Neither that answer nor this one backs the claim up very well, but Wikipedia attributes the parenthetical notation to Euler in 1734, citing this textbook which is available on archive.org. $\endgroup$
    – IMSoP
    Commented Apr 21 at 13:28
  • 1
    $\begingroup$ There is some truth to your statement about juxtaposition, but note that f a b in maths is equivalent to f(a(b)), not f(a, b). So if a and b are just real values, a(b) would be the product of a and b, and f is applied on that product. $\endgroup$
    – G. Sliepen
    Commented Apr 21 at 16:19
  • 2
    $\begingroup$ This answer is misleading. According to Cajori, "A History of Mathematical Notations", volume 2, paragraph 643, function notations both with and without parentheses are quite old: "The use of parentheses for [enclosing the variable of a function] occurs in Euler in 1734, who says, "Si $f(x/a + c)$ denotet functionem quamcunque ipsius $x/a + c$."... About the same time Clairaut designates a function of $x$ by $\Pi x$, $\Phi x$, or $\Delta x$, without using parentheses." Obviously, the notation with parentheses ended up becoming more popular in mathematics. $\endgroup$
    – RobertR
    Commented Apr 21 at 21:28
  • 1
    $\begingroup$ @ChrisDodd Your answer says that juxtaposition, with optional parentheses, has been the standard function application notation for over 100 years, which isn't true. Different fields of math/CS have different standards that have evolved over time, but today the standard in most fields of math/CS is undeniably juxtaposition with mandatory parentheses. ... $\endgroup$
    – RobertR
    Commented Apr 25 at 7:07
  • 1
    $\begingroup$ I wonder if there is a difference between different areas of mathematics, or different parts of the world, or some other reason why we're at odds here. I'm clearly not alone in thinking that a single-parameter function is written $f(x)$ rather than $fx$ or $f \ x$; but you seem very confident of the opposite. It would be really useful to have some context of where you have seen this. $\endgroup$
    – IMSoP
    Commented Apr 27 at 12:07

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .