I have been using functions for Zsh submissions for some time. I typically submit the body alone, as the body can be run as a full program with no modification: afunction arg1 arg2 vs ./aprogram arg1 arg2. If recursion is needed, $0 can be used.

I saw this recent challenge, which is a purely mathematical one. Now Zsh has a math mode and allows math functions which work fairly different from normal functions:

Normal function:

f(){    # define function
    echo "Hello $1"
f world!       # call
s=$(f world!)  # call and capture stdout

Math function:

f(){    # define function
    (( ($1 * $2)**0.5 ))
functions -M f        # define mathfn f, bind it to the function of the same name
functions -M g 2 2 f  # OR define mathfn g which takes min:2, max:2 args 
                      # and bind it to the shell function f
(( k = f(4,9) ))      # call and capture

Math function, but in zcalc (a math-mode REPL provided in Zsh):

:f f ($1*$2)**0.5    # bind (this defines a function named zsh_math_func_f and binds the mathfn f to it)
f(4,9)               # call
k = f(4,9)           # call and capture

How can/should the above math function be scored?

(0) ((($1*$2)**0.5)): This is the body of the function.

(1) ()((($1*$2)**0.5)): This creates an anonymous function, executed immediately and discarded

(2) f()((($1*$2)**0.5)): This is sufficient to bind the body to a shell function, but it hasn't been bound to a mathfn

(3) f()((($1*$2)**0.5));functions -M f

(4) ($1*$2)**0.5 with language as "Zsh zcalc REPL"?

(5) :f f ($1*$2)**0.5 with language as "Zsh zcalc REPL"?

Looking at previous discussions both specific and general, I am unsure how this "double binding" of the function should be accounted for, and how it affects re-usability.

EDIT: The logic in question in Zsh's source

Given a valid MathFunc f, if it is bound to a Shfunc shfunc, it will doshfunc(shfunc, l, 1) and return lastmathval. So the value computed by the last arithmetic expression in the function determines the output of the math function. I wrote my conclusions as an answer. I will consider votes as consensus.

  • 3
    \$\begingroup\$ There's apparently at least some thinking that "REPL languages" violate the snippet loophole (I'm working on a meta question to clarify this), so that'd rule out 4 and 5 if that's the case. \$\endgroup\$
    – Random832
    Oct 22, 2019 at 21:43
  • 4
    \$\begingroup\$ @Random832 REPL languages are perfectly fine, as long as they are labelled as such. It's when they are translated to their parent language they become snippets since they lack the P in REPL (print) \$\endgroup\$
    – Jo King Mod
    Oct 23, 2019 at 3:42
  • 2
    \$\begingroup\$ @JoKing @Random832 Thoughts on (5)? After defining f in this way, zcalc can even be exited and the function persists. \$\endgroup\$ Oct 23, 2019 at 10:55

1 Answer 1

  • Given a shell function f() (( expression )), calling f 42 in a shell context will set a value internal to the shell which would be used as a return value if a math function was bound to it.

  • Assuming these to be the four criteria a function must meet, the largest hurdle to ()((expression)) being a valid submission is what criteria 1 and 3 mean in this context. I claim since "capturing into a name" describes the two steps of binding a shell function and binding a math function, that the anonymous function ()((expression)) is a valid submission. The expression evaluates to an unnamed function, and it does all the things functions do once it is bound to a name.

In the end, if this is to be accepted, the net bytes saved is... 0:

<<<$[($1*$2)**0.5]   # full program, outputs to stdout
()((($1*$2)**0.5))   # anon math function, outputs as math val

This will save bytes when writing a recursive math function, though!


You must log in to answer this question.

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