7
\$\begingroup\$

This is kind of a follow-up to / re-asking of "Should point-free function expressions be allowed when a function is asked for?" with specific reference to the only language I know how to golf in, , where the issue is a little bit pernicious and involved. (Note that there was no final consensus in that meta.PPCG question, so it is technically still open for debate!)

I don't know how to ask this in general without being exceedingly abstract, nor do I have examples in any other languages, but hopefully it's clear enough how this applies to other languages where there are parentheses for modifying evaluation order or operator precedence/associativity.

A little bit of background, for the non-J folk. The J language has an interesting syntax, arguably the main reason it is reasonably competitive against golflangs, called verb trains: to pretend to be more like a functional language, you can jam verbs (AKA functions) together without any extra syntax, and instead of throwing an error, J will compose them in a useful, nontrivial way.

More concretely, suppose f and g are one-argument functions. Then you can write (f + g) to mean a function such that (f + g) y is the same as (f y) + (g y). (Think of the sum of two functions, from first-year calculus.) To oversimplify, any odd-length train of verbs does this kind of thing, in a right-associative manner, and we can put any two-argument function we want instead of +. (There is a version of this for even-length trains, too, but that's irrelevant.)

So here's the issue. If your answer to a code golf question is (f+g), then do you have to include the parens? You don't have to wrap it in parens to name the function, but you do to use it anonymously, since it is not a syntax error to omit the parens:

answer =: f+g
answer 42        NB. this works as intended

(f+g) 42         NB. this works as intended

f+g 42           NB. this is equivalent to   f (+ (g 42))   which is different!

But it gets weirder. For convenience, the f above can be a noun (AKA datatype like array or integer or string) and J will automatically upgrade it to a constant function. So e.g. (2 + g) y is equivalent to 2 + (g y). But now if your submission to the golf is 2+g, then all three examples above will act identically (most of the time). I should note that, having knowledge of the J interpreter, I can say it is reading and evaluating the expression differently in the third case.

And if you want an example of this mattering in a real golf, I came across one just today! If parens are required then my 20 byte solution is (probably) the best possible in J; but if they can be omitted, then my alternative solution is shorter, weighing in at 19 bytes, and ties the current best answer, which is in a golflang.

  • A big argument for not wrapping in parens is that, when you give an expression, you implicitly assume it will be evaluated as-is, not in some context that can possibly change what is meant.
  • A big argument for requiring parens, on the other hand, is that it is only unambiguous when in parens—in J in particular, effectively the only time you can ever omit the parens from a train is when making a simple definition like answer =: f+g.
    • One odd possibility that I personally believe is unacceptable is that, if we require parens, then omitting them in a submission means that answer is invoking the effects of the intentionally unparenthesized code.
  • A third option, entertained in the meta.PPCG question I linked earlier, might be to require that you add the characters necessary to name the function literal. This is unfair for languages like J and R, though, where the assignment operator is longer than one character, so counting the parens would cost less!

This is code golf, however, and there are (at least) 2 bytes at stake here, so there should be some discussion. I tend to err on the side of caution and count the parens in my submissions, but I think by now I've seen this happen enough times to warrant another look. Like I said, the old meta.PPCG question did not come to a consensus, even in the comments.

\$\endgroup\$
14
\$\begingroup\$

Our defaults say that submissions have to be full programs or functions.

REPL "programs" are also allowed, but they have to be labeled as such, and still have to conform to the defaults regarding input and output (which usually boils down to taking input from a prompt and displaying the results on the screen).

For the specific case you mention, I'd argue our defaults apply to J as follows.

A verb train is essentially a lambda or an anonymous function. Those are frequently used in many other languages, and they do not have to be named. The argument for allowing lambdas is that they evaluate to a function, which can be stored somehow to use if as many times as needed.

So just as

lambda x,y:x*x-y*y

which can be used as

diff_of_squares = lambda x,y:x*x-y*y
diff_of_squares(5, 3)

or even

(lambda x,y:x*x-y*y)(5, 3)

is a valid Python answer to calculate the difference of squares of two numbers,

+*-

is a valid J solution which can be used as

diff_of_squares =: +*-
5 diff_of_squares 3

or even

5 (+*-) 3

Just like the parens or assignment to a variable are not counted for Python, they should not be counted for J.

Finally, the fact that

5 +*- 3

does something else (negate 3, compute sign, add to 5) shouldn't matter. When not used as a verb train, +*- is neither a full program nor a function, but merely a snippet (forbidden by default) that requires hardcoding the input arguments to its left and its right. It thus cannot be confused with the verb train +*-, which is a function.

\$\endgroup\$
  • \$\begingroup\$ Another example is mathematica, in which, for example, 'Sign' is considered a complete function definition. 'f:=Sign' is the same as 'f[x_]:=Sign@x' \$\endgroup\$ – Pavel Dec 29 '16 at 5:43
  • 1
    \$\begingroup\$ +1 for the surprisingly parallel Python example. \$\endgroup\$ – DLosc Dec 29 '16 at 20:55

You must log in to answer this question.

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