2
\$\begingroup\$

(This might apply to other languages though I do not know any. I have not found any fitting rule in this meta post: this question is here to hopefully fill this gap. Since this is very specific I don't think it will be of much use in said meta post)

In Brachylog, the main predicate that is queried has two arguments, called the Input and the Output, and can itself only be true or false.

In a sense, this is kind of equivalent to a function in an imperative language, which returns a boolean and which has two arguments.

The input is called that because it is usually what is used to input things, and the output is called the output because we usually say that it is a variable which will "receive" the output.

For example, brachylog_main("test", Z) means query my Brachylog program with "test" as Input and the Output being the variable called Z (which will take the output value).

However, there is absolutely nothing that prevents the following behaviors:

  • Use Output to input things
  • Use Input as a variable to receive outputs
  • Use both Input and Output to input things
  • Use both Input and Output as variables to receive outputs

Obviously, those behaviors can be, in some challenges, more beneficial than the standard input in Input, output in Output. In particular, it is sometimes shorter to input things in Output and output things in Input (so the reverse of the standard use), because of how Brachylog gets executed (from left to right starting with Input and finishing with Output).

Should those altenatives be forbidden?

\$\endgroup\$
3
\$\begingroup\$

If you can pass values for the arguments via acceptable I/O methods, it's acceptable.

On PPCG, we allow a "program" to be a "full program" or a "function". Let's consider these two cases separately:

Full program

A full program on PPCG is fairly objectively definable; we take the language implementation (in this case, the Brachylog interpreter), give it the program as an argument (typically via a file), and run it to see what happens. The program can take and produce output via any of the acceptable I/O methods. Nothing here is specific to Brachylog.

Out of the legal means of I/O for full programs, the following make sense in the context of Brachylog:

  • We can take input via standard input. If input is provided on standard input, the Brachylog interpreter interprets that as setting the Input argument to the program. So far, so good; I doubt there's any controversy that setting the Input to the program is allowed, and this is the way we do it. (Note: In a full program, giving it Input is only acceptable because the interpreter will set the Input as a consequence of text on standard input; having something named Input in a language wouldn't be sufficient in a full program to allow the user to provide input, unless the interpreter gave some mechanism of doing so.)
  • We can take input via a command line argument. If input is provided via the first command line argument, the Brachylog interpreter interprets that as setting the Output argument to the program. The fact that it's named Output has nothing to do with the actual mechanism, though; what matters is that we're providing input to the program in a legal way, and what the interpreter does with it is its problem.
  • We can combine the above two rules to provide two parameters to the program, the Input on standard input and the Output via an argument. (As it happens, I personally disagree with this rule, but it's our current consensus and I'm quite comprehensively outvoted on it. So this post is describing what the rules currently are.)
  • We can take output via standard output. By default, the Brachylog interpreter writes true. or false. here. If the program contains a w command (or one of its variants), it instead allows the w command to provide standard output.

Note what we can't do: we can't take output via the Output, or via the Input. The mechanism via which you do this in Brachylog is to provide a variable name in one of these places (Z is common), and then the interpreter will output text like Z = 4. This means that a Brachylog full program can only provide output via two mechanisms: the w command family; and implicit printing of true. or false.. This means that in a , a full program is likely going to be the best idea. In other cases, using a full program is inadvisable because it can require quite a bit of boilerplate.

Here's an example of a full program that takes input via its Output, and produces output on standard output using the w command. As can be seen, it's much more verbose than just writing it "normally" would be, as a consequence of Brachylog's evaluation order (w takes input only from the left, whereas an Output argument provides input from the right, so you need contortions to get the program back into sequence). As such, although this example is legal, it probably isn't very useful for golfing.

Function

A function on PPCG is less objectively definable. However, a Brachylog predicate is a clear equivalent of a function in most languages; it has arguments, it's reusable, it can be called multiple times.

Out of the legal means of I/O for functions, the following make sense in the context of Brachylog:

  • We can take input via function arguments. All Brachylog functions have exactly two arguments (named ? and ., or Input and Output). The two are treated asymmetrically (because the Input argument naturally occurs early in the evaluation order in Brachylog's syntax, and the Output argument naturally occurs late), but this doesn't change the fact that they're both arguments, and they're both capable of providing input to the function in the normal way. If I have a function ↰₀, I can provide it the integers 1 and 2 as arguments by writing 1↰₀2. So both arguments are usable for input, in the normal way that function arguments are, and their values can be used within the function's definition by writing ? and ., just like function arguments in more normal languages. I don't think any of Brachylog's quirks change our standard consensus for how function arguments work.
  • We can take output via standard output, because legal output methods for full programs are also legal for functions. This means that w is an acceptable form of output from Brachylog predicates (which is definitely handy if we're already using both the arguments we have as inputs!)
  • We can produce output via assigning/mutating the function arguments, in languages where the function's caller will be able to see the assigned values. Unifying the arguments with a value is similar enough to assigning to them (both operations set the value, and the only relevant difference with unification is that you can't subsequently overwrite the value, which doesn't matter here). This allows for idiomatic output via the Output argument ., which is very common in Brachylog (mostly because the syntax does this by default). I can't see any reason, other than convention (and when did code-golf submissions ever feel bound by convention?), that it shouldn't be used to output via the Input either; given that it's acceptable to output via the inputs on PPCG in languages like C (where functions have an actual, defined, return value that can't be made to take input), it should also be acceptable to output via the Input on PPCG in languages like Brachylog (where there's no concept of a return value, but one of the arguments is normally used as a return value by convention).
  • We might or might not be able to produce output via whether the predicate fails or succeeds. At the time of writing, I'd only just added this to the I/O defaults post (as I realised it was missing as a consequence of writing this post, and it's a fairly natural way to output a boolean in declarative languages); as such, there isn't a consensus on whether this is legal or not. However, whatever consensus is found in the I/O defaults post, it should apply to Brachylog too; a failure in a declarative language is very similar to an exception in a language like OCaml (I picked OCaml because using exceptions for flow control is considered acceptable by its community, as opposed to languages like Java where doing so is typically avoided).

Conclusion

In short, my opinion is this: we have general-purpose rules for what forms of I/O are legal, and they apply pretty much directly to Brachylog, so we don't need a special-cases rule. They're fairly permissive, but that makes sense, because they're fairly permissive in other languages too.

Brachylog may have conventions to use function arguments and program input and arguments in a certain way, but in general, we tend to ignore those sorts of conventions on PPCG, and they shouldn't override our general rule. It isn't conventional to output from a function via using print in Python, but it's very common on PPCG as it's a byte shorter than return. So given that we have an established consensus on how I/O works in general, why not use it here too?

\$\endgroup\$
  • \$\begingroup\$ Reading this answer again there's something that sounds unclear to me: why can't we use Z as an argument in a full program to output a variable? "This program needs to be run with the argument X, with a penalty of n bytes" is a fairly common sentence in code-golf submissions, for example. \$\endgroup\$ – Leo Apr 3 '17 at 8:34
  • 1
    \$\begingroup\$ @Leo: Because the output for, say, 4 is Z = 4, not 4. If the Z = happened to be required by the challenge, that would be acceptable. \$\endgroup\$ – user62131 Apr 3 '17 at 12:11
1
\$\begingroup\$

Yes, they should be forbidden

Semantically, there is no reason why Input and Output couldn't be used that way, except for their names (which wouldn't be a problem had they been called A and B instead).

Just like in Prolog, there is no reason why we couldn't use the second argument of a predicate to input things instead of the first.

However, Input and Ouput are not strictly symmetrical in Brachylog precisely because the execution is left to right, and Input is on the very left of a rule and Output on the very right.

Therefore there is actually a difference between the two variables. As such, since Input is the default variable used to input things and Output is the default variable to output things, it should always be that way so as to not get a potentially unfair advantage.

Note: this obviously does not apply to intermediate predicate calls in the code; there you can do anything you wish since it is part of golfing.

\$\endgroup\$

You must log in to answer this question.

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