Pycnolog: Commands ================== This document is a list of the commands that exist in Pycnolog (plus the command combinations that have a different meaning to that which you'd expect from the commands that make them up). The various types of command are notated as follows: * A lowercase letter on its own (e.g. `a`): no-argument command * An uppercase letter plus a hash (e.g. `A#`): command taking a constant * A lowercase letter plus a hash (e.g. `a#`): command taking an enigma; usually but not always does the same thing as the previous case * An uppercase letter, an ellipsis, and a slash (e.g. `A…/`): command taking a block * An uppercase letter, an ellipsis, a slash, and a hash (e.g. `A…/#`): command taking a block and a constant Sometimes these will be merged (e.g. `P` does the same thing when given a number that it does when given an enigma, so there's a combined entry for `P#` and `p#`). ## A: "add", "accumulate" ### `a` Adds together all elements in the input list to produce the output. The sum of an empty list is 0. If the input is a list of lists, this vectorises (essentially wrapping itself in `E…/`). It can vectorise recursively if run on a list of list of lists, etc.. If the input is an enigma for which no bound on its length can be ascertained before the `a` command has to be run, its elements will be assumed to be 1 or greater. (This helps to prevent trivial infinite loops due to the brute-forcer repeatedly trying longer and longer lists of 0s.) ### `a#`, `A#` Adds the input to the argument to produce the output. If the input is a list, this vectorises (essentially wrapping itself in `E…/`). The argument is asserted to not be a list. ### `A…/` Runs the specified block a non-deterministic number of times (including 0), with lower iteration counts being preferred in tiebreak order. The input to the block will be a list consisting of the input to the command, followed by all outputs of previous iterations (in the order they were generated). The output of the command is basically the same, consisting of the input to the command, followed by the outputs of all iterations that ran (in the order they were generated). As a looping construct, the block it introduces forms a new scope. Enigma 3 for this scope will be the number of iterations that will have run by the time the block completes. ### `A…/#` Similar to `A…/`, except that only the outputs of the *n* most recent previous iterations are part of the command. This is very similar to `AB#…/`. However, the input is interpreted differently, being "flattened into" the input to the block (i.e. on the first iteration, the block's input is the command's input, not a singleton list containing the command's input; on the second interation, the block's input is the command's input without its first element, plus the output from the first iteration; and so on). Note that the full list of input and all observed outputs is what's used as the output of the command; that isn't abbreviated to the last *n* outputs. ## B: "behead" ### `b` The output list is the input list, minus its first element. If the input is a number rather than a list, the output will be the absolute value of the input (i.e. we're "cutting the sign" off the start of the number). ### `b#`, `B#` The output list is a suffix of the input list, whose length is given by the argument. ### `B…/` The given block is executed, with the input to the block being the input to the `B…/` command minus its first element. The output of the command is the output from the block, with the first element of the input of the command prepended. (So this effectively lets you run a command on "a list minus its first element".) ## C: "concatenate" ### `c` Asserts that the input is a list of lists (which need not all have the same length). The output consists of the concatenation of these inner lists. When the input is not fully defined, this command could be non-deterministic. In this case, the tiebreak order is based on the lengths of elements of the input; sequences of lengths that are lexicographically earlier are favoured in tiebreak order. (This means that the first input in tiebreak order will be a list of a single list equalling the output; the second input in tiebreak order will be a list of two elements, the knife and tail of the output; and so on.) ### `c#` If the argument is a list, concatenates it to the end of the input list to produce the output. If the argument is an integer, functions like `C#`. ### `C#` This is like `c`, except that the argument is added as an extra element between each of the concatenated lists. Tiebreak order here (for cases where the input is not fully defined) is different too; the primary tiebreak is minimal length of the output, with the secondary tiebreak favouring making the first element of the input as short as possible, tiebreaking by making the second element of the input as short as possible, and so on. (This means that, e.g., `UC+/`, possibly followed by `G1`, can be used to split a list around elements with value 10.) ## D: "digits", "decimal" ### `d#`, `D#` Converts the input into the base-argument number format (e.g. `D2` will output in binary, `D+` in decimal). Unlike mathematical notation, this is little-endian, i.e. the least significant digit will come *first* in the resulting list. So with input 1234, `D+`'s output will be [4,3,2,1]. If the input is a list, rather than an integer, this performs the reverse operation (i.e. a little-endian list of digits is converted into an integer). This version of the command can accept digits that aren't in the range 0 to base−1. (A side effect of this is that if the input isn't fully defined, "unusual" digits can be implied there, and there may be more than one possible input. Tiebreak order in this case favours a lower number of digits; the actual values of the digits will be partially undefined, as opposed to being nondeterministic, and thus do not have a tiebreak order.) ### `d` This is like `d#` except that it guesses at the base to use. If any `d` or `D…/#` commands that appear to its left (literally in the source code; this doesn't take `f`-style function expansion into account) in the same stanza have a constant argument, the base used is that argument. Otherwise, the base used is 10. ### `D…/#` Splits the input into a list of digits, then runs the given block on that list. The constant specifies which base to use. When the block completes running, the digits will be joined back into a number again. As with the other variants of `d`, the least-significant digit comes first. ### `D…/` This is like `D…/#`, but guesses the base to use in the same way as for `d`; however, the default guess is 2 (rather than 10), I if the `D…/` command makes up a whole stanza by itself (in which case the default guess remains at 10). This mechanism means that the distinction between `d…d` and `D…/` can in some cases be used to distinguish base 2 from base 10 without having to give either explicitly. ## E: "element", "each", "every" ### `e` Non-deterministically outputs an element of the input, which must be a list. Tiebreak order favours elements that occur earlier in the list. ### `E#`, `e#` Outputs the *argument*th element of the input. This is 0-indexed, i.e. an argument of 0 requests the first element of the input. Indexing outside the list is an assertion failure. If the argument is a list, instead outputs an index such that the input appears within the argument list at that index. (Again, this is an assertion failure if doing so is not possible.) Tiebreak order prefers to output smaller indexes. ### `E…/` For each element of the input to this command, runs the given block with that element as its input. The output of the command will be a list of the outputs produced on these various iterations. This command makes no attempt to "capture" non-determinism; if there's an assertion failure on even a single iteration the whole command will have an assertion failure (i.e. it won't just omit faililng elements from the output), and if an iteration is non-deterministic, the output will likewise be non-deterministic. The tiebreak order for this is based on the tiebreak order for the first iteration, with the second iteration used as a secondary tiebreak, and so on (lexicographically). As a looping construct, the block it introduces forms a new scope. Enigma 3 will be the index of the element within the list (with the first element being indexed as 0). ## F: "function" ### `F…/` At runtime, this just runs the block that's given as its argument. However, it has some side effects at compile time: * The block in `F…/` has a special case in the parser: it cannot consist of just a single command that takes no argument. In practice, this means that the `F` and `/` must be separated by at least two characters. (The sequence `Fæ/`, where `æ` represents any lowercase letter, is reserved for future expansion.) * If `F` is the last character in the program, it's ignored entirely, as though it didn't exist. (This allows `F` to be used for padding purposes.) * Blocks introduced with `F…/` have the highest possible numbering priority, meaning that they have lower numbers for the `F#` command and are preferentially selected by the `f` command. * Although `F…/` is not a looping command, it nonetheless creates a new scope to run its block. The main purpose of this command, apart from the scope creation, is to "name" blocks so that they can subsequently be referred to from elsewhere in the program. ### `F#` This command has the same effect as running the block or stanza with the given number. (This is resolved at compile time.) This is conceptually similar to copying the contents of the block in question into the program, replacing the `F#`; however, it supports recursion without causing the program to become infinitely long. (So if you wish, you can think of it as the copying happening "lazily" / at the last minute.) The argument to this command cannot be given in base 64 (as the resulting `F/` string would look like a stanza break). ### `f` This command is like `F#`, but the block to run is determined automatically. Specifically, out of the blocks and stanzas which start to the left of the `f` command itself, and which aren't referred to by an `F#` command (anywhere in the program, including other stanzas) or `f` command (to the left of this `f` command within the same stanza, or in a preceding stanza), the block/stanza with the lowest number is chosen. (Note that the current stanza will be chosen if there are no `F…/` blocks that start to the left of the `f` command and no preceding stanzas. Likewise, `F…/` blocks that contain the `f` command in question start to its left, and thus are valid choices to be chosen.) ### `f#` TODO: some sort of `eval`? ## G: "gather", "group" ### `g` The `g` command acts as an evaluation barrier: anything to its left in the same scope must be fully evaluated before anything to its right is. This means that all non-deterministic possibilities for the commands to its left in the scope must be brute-forced before it can even start running. If no terminating brute-force algorithm is known, this will inevitably lead to an infinite loop, and as such is disallowed. If it can be *proven* by the compiler that no terminating brute-force algorithm exists, the `g` instead does the same thing as `G1`. If this can't be proven, running the `g` command is an error (because in the future, it might resolve to either a `g` that the compiler *can* handle due to improvements to the evaluation order algorithm, or to a `G1` because the compiler's proof ability has become better). When it actually does evaluate, all these non-deterministic possibilities will be combined into a single list, in tiebreak order, and produced as the output. Note that this will only take into account possible non-determinism *within the scope* (as non-determinism does not cross scopes). For example, `eg` as a full program (or scoped block) on its own is basically a no-op (although it does assert that the input is a list), as it produces a list made of all elements of the input list; but `eeg` would output a list of all elements of elements of the input list (and thus acts like `c`, except that non-list elements of the outer list will just disappear rather than causing assertion failures). The effect of `g` on enigmas is also worth paying attention to (because non-determinism is "shared" between enigmas, and possibly between them and `g`'s input; thus, combining all the non-deterministic possibilities into one can also cause an enigma to attempt to take on multiple values at once). If an enigma is never mentioned again in the rest of the scope (and isn't visible from the parent scope, like enigma `+` is and enigma `9` usually is), its definition (or conflicting definitions) are simply ignored at this point. Alternatively, if an enigma *is* mentioned in the rest of this scope, `g` will assert that all the possible definitions for it are consistent with each other (and the resulting definition of the enigma will be the intersection of all the previous definitions). This may lead to an assertion failure if the existing definitions were incompatible. Finally, if there's non-determinism in the mentioned enigmas, this will be preserved, with the output of `g` in each of the non-deterministic branches reflecting the values of enigmas in that branch. #### `gg`, `gG…/`, etc. If the no-argument `g` command is immediately followed by any variant of the `g` command, it's interpreted as `G0` rather than `g` (because the second command would otherwise be useless, given that `g` removes all non-determinism from the scope and `g` variants are used to manage nondeterminism). ### `G#` `G#` is like `g`, but outputs only the first few elements in tiebreak order: the number of elements given as an argument. So for example, `G2` will output a list consisting of only the first two elements in tiebreak order. Because `G#` discards all elements beyond a given point, they need not be calculated; thus, unlike `g`, which requires any non-determinism within the scope so far to be fully brute-forced out, `G#` will attempt to brute-force in tiebreak order, and stop when enough results have been found. This thus potentially allows it to be useful when no terminating brute-force algorithm is known. Note, however, that you need to be careful to ensure that results will be found along the first "branch" that the algorithm considers; it's thus mostly only useful when the tiebreak order is infinite only in its major sort key. ### `g#` `g#` is equivalent to `G#`, but taking an enigma as argument; this can be used to produce "some" results when you don't know how many (and are planning to take a prefix of the results later on). This variant of the command additionally replaces partial definition with nondeterminism; because there's pretty much no limit to how complex partial definitions can be, a full specification for tiebreak order for this would be unreasonable to give, but where possible, the implementation will attempt to find something in the partial definition that it can keep as close to 0 as possible. For example, `X1g0`, if run with an undefined numerical enigma as its input, will output some list of prime numbers in ascending order, with enigma 0 being defined as the length of that list. The primary tiebreak order for `g#` is to favour smaller arguments (i.e. shorter output lists). #### `gh` `gh` would gather all possible outputs, then keep only the first. That's inefficient, and thus it is instead defined to short-circuit (i.e. as shorthand for `G1h`, which would be equivalent to `gh` in any case where it terminates). This operation is in turn equivalent to the "cut" operation found in some declarative programming languages, such as Prolog; it discards any possibilities other than the first possibility encountered up to that point. #### `G0` `G0` is also a special case (as ignoring everything to its left and producing an empty list wouldn't be a particularly sensible operation). Instead, it's a way of writing `G…/` with an empty block as argument (which isn't otherwise syntactically possible). ### `G…/` `G…/` is a "group by" operation. Its behaviour is equivalent to doing `g`, then ascending-sorting the input using the block in question as a method of deriving sort keys from elements, grouping together elements that sort as equal according to the key into lists (singleton lists if necessary), and then doing `e` to reintroduce non-determinism at the block level. For example, `Gl/` will, given a non-deterministic input, non-deterministically output a block of possibilities for that input that all have the same length; tiebreak order for the new non-determinism will favour shorter lists first. A consequence of these rules is that `G…/e` will act as a method of setting a new tiebreak order (tiebreaking via whatever criterion appears in the block), without actually changing the non-deterministic possibilities in the input. (It will, however, still act as an evaluation barrier; changing the tiebreak order is not an operation that can be easily implemented without one.) Non-determinism inside the block inside `G…/` is effectively moved "before the evaluation barrier", i.e. the evaluation barrier comes entirely after the block. This means that if the block is non-deterministic, it can cause an element to be placed into multiple groups (or the same group multiple times). Similarly, if the output of the `G…/` block is only partially defined, it will be labelized (i.e. all possible valid values for it will be brute-forced, potentially causing an infinite loop!), and this labelization will be visible in the resulting values. (For example, `r6w6` specifies that its output – and enigma 6 – are in the 1 to 5 inclusive range, without setting up full non-determinism or a tiebreak order. `r6w6g` likewise returns a list containing a single element, which is partially defined as equalling enigma 6 and being in the 1 to 5 inclusive range. `r6w6G0`, on the other hand, will non-deterministically output one of five different lists, `[1]`, `[2]`, `[3]`, `[4]`, or `[5]`, in that tiebreak order; enigma 6 will be fully defined in each non-deterministic branch, and equal the element of the output list.) The order of the brute-forcing during labelization is currently unspecified, but may be specified in the future. However, if there's only one partially defined value involved, and it's an integer, values closer to 0 will come earlier in the resulting tie-break order. ### `UG…//` When `G…/` is inverted using `U…/`, this reverses the sort order (rather than swapping the input and the output, like normal; doing so would be rather mind-bending to think about…). So the sort will be in descending, rather than ascending, order by key. ## H: "head" ### `h` The output is the first element of the input list. ### `h#`, `H#` The output is the input list, with the argument prepended as an element. ### `H…/` The block is executed, using the first element of the command's input as the block's input. The output of the block will be used as the first element of the command's output; all elements but the first of the command's output will be taken from the corresponding elements of the command's input. In other words, this operates "on the head" of a list, keeping the rest of it unchanged. ### `H…/#` Like `H…/`, but operating on an element with a specific index (given by the integer argument), rather than on the first element. ## I: "input/output", "index" ### `i` The `i` command uses its input as output from the program as a whole (as opposed to output from any given command). This would normally be to a screen (or comparable device intended to display output to humans). The output at the command level is equal to the input. The output is formatted using JSON notation (i.e. lists in square brackets, with comma-separated elements; integers in decimal), and appearing on a line of its own. If the input is not fully defined, extensions to the notation will be used to show what is known (e.g. purely unknown list elements will be represented with capital letters, reusing a letter to show that two elements are known to be equal). When a value is non-deterministically output, all possibilities are output, in tiebreak order. In fact, tiebreak order more generally determines how multiple outputs are ordered; for example, if two `i` commands appear in a program, the command which would have more control over tiebreak order will get to produce its output first (even though, of course, the command itself is not non-deterministic and thus has no desire to exert any such control). Note that because `i` can see multiple non-deterministic possibilities at once, it could be expected to have an effect on evaluation order, like `g` does, in order to ensure that the output can always be output correctly. However, the reverse is true; `i` effectively comes *last* in evaluation order, and any outputs that turned out to be in "dead ends" won't be printed. (However, if there's a potential infinite loop in the program, potential dead-end outputs may be printed anyway, and subsequently "un-printed" via deleting them from the screen once their dead-end nature is confirmed. Likewise, later outputs in tiebreak order may be displayed before earlier outputs, with the earlier outputs inserted into the right place when they become available.) This does not extend, however, to outputting the same thing multiple times due to non-determinism that comes later in tiebreak order than the `i` command itself; no piece of output will be output too many times. #### `Ui/` The input and output to `i` are the same, so reversing them would be redundant. As such, `Ui/` implements a different command: it causes its input to be rendered into Unicode codepoints in the most natural way, but the resulting list of codepoints is returned as the command's output rather than being used as output from the program as a whole. ### `I#` The `I#` command is similar to `i`, but instead of outputting a data structure directly, it outputs arbitrary text. The argument is a constant that specifies how to encode the input into a text format. If the argument is a list, it'll be interpreted as a list of codepoints in the format. If it's an integer, it'll be converted to digits in the most "natural" base for the encoding, and output in big-endian format (i.e. the least significant digit comes last). The supported arguments mostly show the approximate number of bits per character, and include: * 0: raw, unencoded, bits (8 bits per byte) * 1: binary (`0` and `1`, trailing newline) * 3: decimal (`0` to `9`, trailing newline; maybe a leading `-`) * 4: hexadecimal (trailing newline) * 6: base64 (`A` to `Z`, `a` to `z`) * 7: ASCII (NUL to DEL) * 8: Windows-1252 (NUL to `ÿ`); can also be used for Latin-1 * +: UTF-8 (arbitrary bit count) No trailing punctuation or whitespace is added unless shown in the above table. #### `UI#/` Just as with `Ui/`, `UI#/` will produce output as the command's output rather than outputting it to the user. ### `i#` Takes input interactively from the user. That input will be asserted to equal the argument (i.e. it'll be "stored in" the given enigma). The input to the command itself will be used as the output to the command itself. The user will be given a prompt, specifying what sort of input is required. (This will be determined by looking at the partial definition of the enigma in question.) Invalid input will be rejected; blank or otherwise "cancelled" input (e.g. end-of-file) will cause an assertion failure. This command acts as an evaluation barrier, to ensure that inputs are sensibly ordered with respect to outputs. If there's no need to take input interactively at a certain time, it's normally simpler to use command-line arguments for input. ### `I…/` Attempts to find an index of the input list with certain properties. (The first element of a list has index 0.) The output will be an index *y* for which for each index *x* distinct from *y*, running the block with its input as the *x*th element of the list and its output as the *y*th element of the list succeeds. Tiebreak order favours smaller *y*; and in cases where the input list is not fully defined, it favours shorter input lists. As a looping construct, the block it introduces forms a new scope. Enigma 3 in this scope will be the value of *x*. ## J: "juxtapose" ### `j#`, `J#` These commands output a list that consists of a number of copies of the same element; the number of copies equals the argument, and the element itself equals the input. So for example, `J3` outputs a list with three elements, each of which is equal to the input. ### `j` With no arguments, the `j` command is essentially an inverse of the version with an argument: it takes a list as input, and asserts that all elements of that list are equal. The output is the element that that list contains. ### `J…/` The `J…/` command runs the given block some number of times (in essentially the same way as the `X…/` command), and thus introduces a new scope. The difference is that the number of iterations is not specified in advance; rather, the command can end once it's seen the same output value from the block twice, not necessarily consecutively (although non-deterministically, it can still continue at this point, but doing so is disfavoured in tiebreak order), and it must end if an assertion failure occurs (i.e. an assertion failure is treated identically to a repeated output, except that continuing after that point is obviously impossible). The output of the command is the list of all observed outputs from the command (not including the second copy of the output that was observed twice). Enigma 3 for the new scope is the number of output values that will have been observed by the time the block ends (i.e. 1 on the first iteration). ### `J…/#` The `J…/#` command is similar to `J…/`, in that it runs the block given multiple times, and requires repeated output or failures to be able to end (whilst being able to continue running beyond that). However, the input is a list, and the argument is a number of elements; the input to each run of the block will be a list with a number of elements equal to the argument, and whose elements are taken from the input list and/or the outputs of previous iterations, non-deterministically. In order for the command to be able to end, *every* possible list of the appropriate length must be tried at some point during the computation (implying that sufficiently many duplicate outputs and/or assertion failures were seen that all distinct input lists have been tried), in every one of its permutations. So this can be seen as a closure operator, transitively closing a set under a given operation. The output is the set of output elements that were observed during the operation (the inputs won't be explicitly added to or removed from this set, i.e. they'll be included only if they were also seen as outputs). The set will be represented as a list, ordered in such a way that any element of the list can be produced, via the block, from elements of the inputs and elements that appear earlier in the list (it might also have other ways to be produced). Tiebreak order is undefined and subject to change. If the block is nondeterministic, each of its possible outputs will be considered to have been generated separately, e.g. the stanza `4gJw/1` will output the list [0,1,2,3] in some order (because each of those elements can be produced by `w` from the input element 4). Likewise, if the block fails, the command as a whole will continue, simply treating the failure as contributing no outputs. ## K: "knife" ### `k` The output list is the input list, minus its last element. When the input is an integer (rather than a list), this instead outputs the sign of that integer (-1 for a negative input, 0 for zero, 1 for a positive input). ### `k#`, `K#` The output list is a prefix of the input list, whose length is given by the argument. ### `K…/` The given block is executed, with the input to the block being the input to the `K…/` command minus its last element. The output of the command is the output from the block, with the last element of the input of the command appended. (So this effectively lets you run a command on "a list minus its last element".) ## L: "length", "list" ### `l` Asserts that the input is a list. The output is its length. ### `l#`, `L#` Asserts that the input is a list, and the argument is its length. The output is equal to the input. ### `L…/` Runs the given block in a scope of its own (with the input to the block being the input to the command, and enigma 3 being initially undefined). Returns the same result `gl` would if placed at the end of the block (i.e. a count of the number of nondeterministic possibilities that exist at the end of the scope). Bear in mind that because scopes isolate nondeterminism, the possibilities that are counted must have been generated inside the scope (as each possibility runs in a separate `L…/` block). ## M: "minus", "most" ### `m` Takes differences of successive pairs of elements in the input list (its "deltas"), to produce the output. That is, the first element of the output is the second element of the input minus the first element of the input, the second element of the output is the third element of the input minus the second element of the input, and so on. The resulting output list will be one element shorter than the input list is. ### `m#`, `M#` Subtracts the input from the argument to produce the output. (If you wanted to subtract the argument from the input, use `ym#`/`yM#` to reverse the argument order, or `M0` in the case where you want to subtract 1 from the input.) If the input is a list, this vectorises (essentially wrapping itself in `E…/`). #### `M0` As a value can be subtracted from 0 using `u`, `M0` instead subtracts 1 from the value (contrast with `M1` which subtracts the value from 1). ### `M…/` Runs the given block on each element of a list (i.e. each element of the block will in turn be given as input to the list). Then, out of the elements for which the block succeeded (i.e. did not have an assertion failure), non-deterministically returns an element of the input list for which the output was at least as great as any other such output. Because knowing more about the input to this command can increase the number of non-deterministic possibilities for the output (via causing assertion failures), it serves as an evaluation barrier; anything written after the `M…/` in the same scope will run after it, and anything written before it in the same scope will run before it. This is to prevent optimisations interfering with the correctness of the program. As a looping construct, the block it introduces forms a new scope. Enigma 3 will be, as usual, the index within the list of the element that's currently being considered. ### `Mg/` Placing `g` at the start of a block is useless, so `Mg/` has a special meaning: it first does `g`, then takes the maximum element of the resulting list. (In other words, this is like `gM/`, except that `M…/` does not syntactically allow an empty block, so a workaround like this is necessary.) ## N: "n copies", "not equal", "not" ### `n` The output is the input with zero or more of its duplicate elements non-deterministically removed (i.e. duplicates in the input could potentially remain in the output, but might be removed; however, for every distinct element that appears in the input, it'll also appear in the output). The first copy of an element cannot be removed this way. Tiebreak order favours shorter outputs, and outputs where later elements are removed (all outputs in which the last element is removed will be favoured over outputs of the same length in which the last element isn't removed). The first output in tiebreak order, therefore, will be the input list without duplicates. If the input is not fully defined, there may need to be a tiebreak order for the inputs, too; this favours shorter inputs, taking precedence over favouring shorter outputs. ### `n#`, `N#` When the input is a list, asserts that each element of the input appears a number of times in the input that's exactly equal to the argument. Thus for example, `N1` asserts that each element of the input appears exactly once in it, i.e. all elements of the input are distinct. The output equals the input. In the case where the input isn't fully defined, this is non-deterministic; shorter inputs come first in tiebreak order. This command is also subject to the "no negative assertions on undefined elements" limitation, meaning that if any *elements* of the input or output aren't fully defined, they may potentially be considered distinct even if they're equal, or later turn out to be equal. (The chosen evaluation order will attempt to avoid this case, unless it really has to use it.) When the input is an integer, this works quite differently; the output is the bitwise-XOR of the input and argument (i.e. the bits in which the two are not equal). ### `N…/` This command is an evaluation barrier, like `g` is; anything that appears to its left must be fully evaluated before it runs, anything to its right won't be evaluated until after it's finished running. The block given as argument is run, with the same input as the command's input, then its output is labelized (i.e. a brute force attempt is made to find at least one possible *concrete* value for the block's output, with all enigmas fully defined to arbitrary values). If there's an assertion failure in this process, then everything (especially the amount of definition in enigmas) is reset to the state it had when the `N…/` command started running, and it succeeds, with output equal to input. If, however, there is no assertion failure in this process (meaning that, based on the amount of knowledge at the time that the `N…/` command runs, it can't be proven that the block can't succeed), the `N…/` command has an assertion failure (making the values of all enigmas irrelevant, as this part of the scope is no longer in use). It must be stressed that this cannot be used to make negative assertions on undefined elements (there is *no* way to make negative assertions on undefined elements); `Nj/` does not assert that its input contains two differing elements, rather it asserts that its input can be *proven* to *already* contain two differing elements. So `r1NJ/` (with undefined enigma 1) doesn't define enigma 1 to "a nonempty list where the elements aren't equal" (from its default definition of "a nonempty list"); rather, it assertion-fails, as there's nothing currently preventing enigma 1 containing two equal elements. (This should make it clear why the command's an evaluation barrier: otherwise, its meaning could substantially change as a result of later definition of an enigma it's operating on.) As such, this is mostly only useful for making negative checks about values that are already fully defined. (You can also exploit the fact that `N…/` never adds extra definition to any enigma; a double-negative `NN…//` will check the block to see if it's capable of succeeding on the input, but not actually make any changes to enigmas for the possible success that it finds.) ## O: "order", "or" ### `o` Sorts the list that's given as input, in order to produce the output. (For those people who run this with an input that isn't fully defined: this is defined as "the output is a permutation of the input, and assert that the output is sorted", with tiebreak order as in `p`.) #### `Vo/` This command would otherwise be useless (if you really wanted to verify that every element of the input was a list, you could just use `Vl/`, which would be clearer and more efficient). As such, it's given a different purpose: it verifies that the input list is sorted. The output is equal to the input (unlike `Uo/`, where the output could be a permutation of the input). ### `O…/` This command has two nondeterministic possibilities: * Doing nothing, with the output equalling the input, and the block ignored. * Ignoring everything that comes *before* the `O…/` command in the same scope, and running the block with the block's input equalling the scope's input (i.e. the block's input is enigma 8). The output is the block's output. The first possibility is favoured in tiebreak order. This command exists as a method of introducing nondeterminism into a program manually, without having to rely on nondeterministic builtins (and thus, in turn, allowing custom nondeterministic functions to be implemented). ## P: "permutation" ### `p#`, `P#` Outputs a specific permutation of the input list. The argument specifies which permutation. Permutations are specified using a *permutation number*. Permutation numbers are determined by looking at the operation of the same permutation on a hypothetical sorted list with distinct elements and the same length; permutations which produce lexicographically smaller results when given such a list have lower permutation numbers. (0 is the smallest permutation number, corresponding to a null permutation that doesn't rearrange the input at all. The highest permutation number is equal to the factorial of the number of list elements minus 1, and represents a reversal of the list.) In the case where the permutation number is not fully defined, it will be chosen non-deterministically, with lower numbers coming first in tiebreak order. ### `p` Outputs any permutation of the input list, non-deterministically. Tiebreak order is by permutation number, with smaller permutation numbers coming first. ### `P…/` Sorts the input list by a key to produce the output. The sort key for each element is determined via running the given block with that argument as input; the block's output determines the sort key. ## Q: "quotient", "subsequence" ### `q#`, `Q#` Returns the input divided by the argument, rounding towards negative infinity. The argument must be an integer. (The input can be a list, in which case this vectorises, taking the quotient of every list element.) ### `q` The output is a (not necessarily contiguous, but with order preserved) subsequence of the input (chosen non-deterministically). Tiebreak order favours longer outputs (and shorter inputs, if those aren't fully defined either), with a secondary tiebreak to preserve earlier elements into the subsequence (preserving the first element is lexicographically more important than preserving the second, etc.). ### `Q…/` Runs the given block on a non-deterministically chosen subsequence of the input, analogously to the way `B…/` runs the given block on the elements of the input other than the first. There's an assertion that the output of the block has the same length as the input of the block (otherwise it'd be impossible to insert the new elements into the right positions relative to the old positions). Tiebreak order is the same as for `q`. ## R: "restart", "replace", "running" ### `r` Ignores its input, and outputs the value of enigma 8 (i.e. the value that was present at the start of the block). ### `r#`, `R#` Ignores its input, and outputs its argument. This is a way to introduce constants into a program. Warning: at the start of a stanza, `R` is implicit upon seeing a digit or punctuation mark, and thus you *must* leave off the `R` in that context. `R/` at the start of a stanza marks a comment. `R` and a digit at the start of a stanza is currently reserved for future expansion. #### `r8` `r8` would obviously be redundant to `r`, so has a separate interpretation: ignoring both the input *and* the output. In other words, both the input and output are effectively connected to (different) fresh enigmas with no definition, and which aren't linked to any other enigmas in the program. #### `yr#`, `yR#` Swapping the input and argument of these forms of `r` is clearly useless, because that would ignore the argument and output the input, i.e. a pure no-op. Instead, these are used to access *command-line* arguments; the input is ignored, and the command-line argument at the index specified by the constant/enigma given as argument is output. Argument 0 is the file containing the compiled Pycnolog program; argument 1 is the initial value used when running the program (i.e. enigma 8 of the scope formed by the last stanza as a whole); argument 2 is the next argument (enigma 4); argument 3 is the next argument (enigma 5); arguments 4 onwards are arguments beyond that. This gives an assertion failure if the argument in question doesn't exist (so `yR2` and `r4` aren't quite equivalent; the latter gives access to a "global enigma 4" if there was at most one command-line argument to the program, the former will just fail in that case). ### `R…/` Runs a block iteratively on an input list, as follows: first the block will be given the first two elements of the block as input, and executed; then it will be given the output of the block's first execution and the third element of the input (as a two-element list) as input, and executed; and this process will continue until the entire list has been processed. This operation is similar to `A…/2`, but it takes a list as input, rather than a single element. The output will consist of a list of all the partial values encountered during execution: the first element will be the first input to the first iteration (i.e. the first element of the input list); the second element will be the output of the first iteration (the first input of the second iteration); the third element will be the output of the second iteration (the first input of the third iteration); and so on, until the last element is the output of the last iteration. This will therefore produce a list of the same length as the input list. As an example, `Ra/` will produce a "running total" operation, mapping, e.g., [1,2,3,4,5] to [1,3,6,10,15]. As a looping construct, the block it introduces forms a new scope. Enigma 3 will be the number of elements of the input list that have been consumed so far (thus, it will be 2 on the first iteration). ## S: "substring", "split" ### `s` The output is a contiguous (and with order preserved) subsequence of the input (chosen non-deterministically), i.e. a "substring". Tiebreak order favours longer outputs (and shorter inputs, if those aren't fully defined either), with a secondary tiebreak to start the substring as early in the input as possible. The empty substring is a possible output, as is the input itself. ### `s#`, `S#` This command is similar to `Uc/`, i.e. it entirely splits the input list into substrings which when concatenated form the original input. However, it contains assertions on the substrings in question. If the argument is not an integer 0, it gives the size of each substring (and all the resulting substrings will have equal size; thus, you get an assertion failure if the argument does not divide the length of input). Partially defined inputs or arguments can lead to non-determinism, in which case the length of the input is the primary tiebreak (lower is better), the value of the argument the secondary tiebreak (higher is better). When the input is an integer, rather than a list, this has an entirely different purpose: performing a modulus operation (i.e. "the amount left over after splitting"). This always returns a value from 0 to (argument-1) inclusive. If you want to split around a given element (rather than into blocks of a given length), use `UC#/`. #### `S0` Splitting a list into zero-length substrings is meaningless, so `S0` has a different meaning: it splits the input into substrings each of which consists only of repeats of a single element. This is non-deterministic, with the same tiebreaks as `Uc/`. ### `S…/` Runs the given block on a non-deterministically chosen substring of the input, analogously to the way `B…/` runs the given block on the elements of the input other than the first: the input of the block will be a substring of the input to the command, and the output of the command will be based on the output of the block, with all elements appearing before the chosen substring in the command's input prepended, and all elements appearing after the chosen substring in the command's input appended. Tiebreak order is the same as for `s`. ## T: "tail" ### `t` The output is the last element of the input list. ### `t#`, `T#` The output is the input list, with the argument appended as an element. ### `T…/` The block is executed, using the last element of the command's input as the block's input. The output of the block will be used as the last element of the command's output; all elements but the last of the command's output will be taken from the corresponding elements of the command's input. In other words, this operates "on the tail" of a list, keeping the rest of it unchanged. ## U: "un-", "upend" ### `u` Reverses the list that's given as input, to produce the output list. If you do this on an integer rather than a list, the output will be minus that integer. ### `U…/` Runs the block with its input and output connections swapped, i.e. the output of the block will be connected to the input of the `U…/` command, and vice versa. For example, `Ul/` outputs a list whose length is equal to the input. It can be confusing to think about how this operation works, given that most commands specify how they produce an output from an input, not vice versa. The way to think about it is that `U…/` produces a temporary enigma that's provided as the input to the block, and then asserts that the output from the block matches the input to the `U…/` command. If it does, the temporary enigma in question is output (with, of course, likely definition based on what the commands did). Unlike in Prolog/Brachylog, `U…/` does not imply an evaluation order; this will be based on the semantics of the commands in question. In particular, the commands inside the block may be evaluated in reverse order; doing so is often more efficient and may help to keep the program execution finite. ## V: "value", "variable", "verify" ### `v#`, `V#` Asserts that the input, output, and argument all have the same value as each other. ### `V…/` `V…/` is basically the same as `E…/`, except that the output of the command is the same as its input; the block is only being run to see if there are assertion failures. (This also means that non-determinism inside the block does not escape it, and the output from the block is entirely ignored; it just has to exist.) As such, it's effectively asserting that the block can succeed on every element of the input. If the input is not a list, then the block is run with the same input as the command (rather than running the block on each element of the list). Again, the block's output is ignored, non-determinism does not escape it, and the like. Because this can be a looping construct under some circumstances, it creates a scope. When acting on a list, enigma 3 will be the index of the element being examined within the list (0-indexed, thus the first list element will lead to a value of 0 for enigma 3). When acting on an integer, enigma 3 will be undefined. If the block is one which cannot possibly have an assertion failure (because all the commands it contains are ones that cannot fail), this acts like `UV…//` instead. #### `UV…//` Similar to `V…/`, but instead of ignoring the output of the block, asserts that it's equal to the input. This variant of `V…/` never iterates over a list, i.e. the block is only ever run once. ### `v` Non-determinstically forms an output list using elements from the input. Unlike with `Un/`, there's no requirement that the elements first appear in the same order, or that all elements from the input appear; and unlike with `q`, elements from the input can appear multiple times in the output. Tiebreak order prefers shorter outputs, shorter inputs, and outputs where the indexes used from the input are lexicographically smaller. (For example, running `v` on the list [2,1] gives a tiebreak order of [], [2], [1], [2,2], [2,1], [1,2], [1,1], [2,2,2], etc..) ## W: "within" ### `w` Produces a partially defined integer output that's greater than or equal to 0, and strictly less than the integer input. ### `W#`, `w#` Asserts that the input is greater than or equal to 0, and strictly less than the argument. The output is the same as the input. If the input is a list, the operation vectorises, performing the same assertion on every element of the list (with the assertion failing if any list element is out of range). #### `UW#/`, `Uw#/` This otherwise redundant command sequence is like `W#`/`w#`, but asserts that the input is *greater than or equal to* the argument, rather than less than it. (This is not equivalent to `yW#`/`yw#`, which would assert that the input is *strictly greater than* the argument.) #### `W0`, `W1` These two commands are reundant (`W0` would always fail, `W1` would be redundant to `V0`), so instead they produce lists of integers: `W0` produces a sorted list of integers from 0 inclusive to the input exclusive, `W1` from 0 exclusive (i.e. 1 inclusive) to the input inclusive. In the case that the input and output are both partially defined, tiebreak order prefers shorter outputs, i.e. smaller inputs. ### `W…/`, `W…/#` This is effectively a "for" loop; the block's body will be run multiple times, with the block's input being chosen as a value that's greater than or equal to 1 (or whatever value is specified as the integer argument, if there is one), and less than or equal to the input. (Note that unlike `w`, which is 0-indexed, this is 1-indexed.) The output will be a list consisting of the outputs from the block. Non-determinism and assertion failures within the block become non-determinism and assertion failures of the block as a whole. As a looping construct, this introduces a new scope. Enigma 3 will be initially undefined (as enigma 8 is effectively acting as the loop counter in this case). #### `W…/1` This otherwise redundant command sequence is a 0-indexed version of `W…/`; the block's input is greater than or equal to 0, and less than the command's input. (Compare `W…/0`, where the block's input is greater than or equal to 0, and less than *or equal to* the command's input.) ## X: "times" ### `x` Multiplies together all elements in the input list to produce the output. The product of an empty list is 1. Alternatively, if the input is an integer (rather than a list), produces a list of (positive) prime numbers that can be multiplied together to produce that input. (This is an assertion failure if the input is negative or zero.) If the input is an enigma for which no bound on its length can be ascertained before the `x` command has to be run, its elements will be assumed to be 2 or greater. (This helps to prevent trivial infinite loops due to the brute-forcer repeatedly trying longer and longer lists of 1s.) ### `x#`, `X#` Multiplies the input with the argument to produce the output. If the input is a list, this vectorises (essentially wrapping itself in `E…/`). #### `X1` As multiplication by 1 is pointless, `X1` instead asserts that the input is a prime number. The output is equal to the input. If the input is a list, this vectorises. ### `X…/`, `X…/#` Runs the given block multiple times. The input of each iteration is the output of the previous iteration (with the input of the first iteration being the input to the `X…/` command, and the output of the last iteration being used as the output of the `X…/` command). The number of iterations is specified by the numerical argument, defaulting to 2 if this is not given. As special cases, giving `0`/`1`/`2` as a numerical argument will use an *enigma* for the number of iterations instead (enigmas `0`, `4`, `6` respectively). As a looping construct, the block it introduces forms a new scope. Enigma 3 is 0 on the first iteration, 1 on the second, 2 on the third, and so on (note that this is a different numbering scheme than the usual one for iterative loops). ## Y (not actually a command, but listed here for completeness) ### `y` This is a prefix that's given to another command to change the way in which it takes its arguments. For example, `ye` is not two commands `y` and `e`, but a single command `ye` (which *parses* the same way that `e` would, but does not have the same meaning). The exact meaning depends on what syntax variant the command being modified uses. (In the below, `æ` represents any lowercase letter, `Æ` any uppercase letter.) #### `yæ` Currently undefined and reserved for future expansion. #### `yæ#`, `yÆ#` When `y` is applied to a command with a single integer or enigma argument, it causes the command to be run with input and argument swapped; the command's input is taken from the stated integer/enigma, the command's argument from the input to the combined command. (Compare `U…/`, which runs a block with input and output swapped. `y` has to be a special case in the syntax, rather than taking a block like `U…/` does, because despite having inputs and outputs, blocks don't have arguments; only commands have arguments.) Most of the time, `æ#` and `Æ#` are the same, i.e. commands don't care whether they're taking a constant or enigma as argument. For the few that do, this modification forces the enigma version to be used, i.e. the behaviour of both `yÆ#` and `yæ#` are based on that of `æ#`. #### `yÆ…/`, `yÆ…/#` Currently undefined and reserved for future expansion. ### `y#` Just like `y`, this is a prefix to a command; unlike `y`, this now comes with an enigma as argument, so the modified command will have the enigma as argument in addition to any arguments it would otherwise have. #### `y#æ` This effectively uses the `æ#` command to combine corresponding elements of two lists of the same length; the first element of the `y#æ` command's input and the first element of the enigma (which must be a list) are used to give the input and argument for `æ#`, then the same is done for the second, third, etc. arguments, and eventually the result is combined into a single list. #### `y#Æ…/` Used to provide an enigma as an argument to a block-and-integer command (thus allowing the integer to not be hardcoded). The effect is the same as that of `Æ…/#`, except that the number is treated as an enigma rather than an integer. #### `y#æ#`, `y#Æ#`, `y#Æ…/#` Currently undefined and reserved for future expansion. ### `Y…/` The exact meaning of this depends on the first command inside the block. There are a few defined cases (with other cases being reserved for future expansion): #### `Yæ#…/`, `YÆ#…/` This is a fold command (similar to `Ræ#…/t`); it runs the block repeatedly, one iteration for each element of the input list. However, there's something of a permutation of inputs and arguments going on, as usual for `y`. Each iteration but the first uses the output of the last iteration as its input, and replaces the argument of the `æ#`/`Æ#` command with the corresponding element of the input list. The first iteration still does the argument replacement, but takes the argument actually given to the `æ#`/`Æ#` command in the block as its input (because there's no previous iteration to take the value from.) Note that if `æ#` and `Æ#` differ, then the behaviour of `æ#` is used (because the argument is not a constant), regardless of the capitalisation within the block (that capitalisation serves only to indicate whether the input on the first iteration is an enigma or a constant). #### `Yæ…/` This is similar to `Yæ#…/`; however, the first element of the list is used as the input for the first iteration, as no element has been explicitly specified for that purpose. The first iteration therefore uses the second element of the list as the argument to `Yæ#…/`, and the number of iterations is 1 less than the list length. (In the case that the list has length 1, this basically just returns its only element, with `æ#` not executing at all.) `Yæ/` (with a single command inside the block) can be seen as a method of changing `æ#` from a command that takes an input and an argument separately, to a command that takes two or more inputs via a list given as its input. ## Z: "zip" ### `z` Asserts that the input is rectangular (i.e. it's a list of lists, and each of the interior lists has the same length). To produce the output, the input is transposed, i.e. the first element of the output is a list of first elements of elements of the input, the second element of the output is a list of second elements of elements of the input, and so on. ### `z#` Produces a list by combining corresponding elements of the input list and the argument list, which must have the same length. Each element of the output list will be a two-element list, of which the first element comes from the corresponding element of the argument, and the second element comes from the corresponding element of the input. If either or both of the input or the argument is an integer (rather than a list), this works like `Z#` instead. ### `Z#` Produces a two-element list. The argument becomes the first element of the output list, the input becomes the second element of that list. ### `Z…/` Runs the given block on each element of the input list (i.e. each element of the input list is separately used as input to the block in question). The output and input of each iteration are paired into a 2-element list (in that order), and these pairs are grouped into a new list, with the same length as the original list. This can also be used when the input is an integer (rather than a list), in which case the block is run on that integer, and a two-element list is returned, consisting of the block's output and input in that order. Tiebreak order here functions the same way as with `E…/`. As a command that can potentially be a looping construct, the block it introduces forms a new scope. When running on a list, enigma 3 will be set to the index of the list element being considered (i.e. when the first element of the list was used as input, this will be 0, when the second element of the list was used as input, this will be 1, and so on).