Used by Wolfram expressions.

Might it be worth explaining Wolfram expressions? Given that this is the first thing on the reference page, and the first mention of Wolfram expressions, it seems like that might be helpful.

I don't actually know what a Wolfram expression is... best I could do is to link to the Types section of the reference.

“y

Starts a literal string (a string containing these command characters, excluding ”, ¶ or ⸿). (TIO: ¶ or ⸿ will also be quoted, but the deverbosifier erroneously converts \n or \r.)

Upon first glance, I wasn't quite sure whether this was a copy-paste error or an actual token. I think it's an actual token. Therefore, an example of a “y string would be helpful to disambiguate. Also, the way the indent is formatted could be made clearer that it's an extension of the upper-level quote mark. If it can be styled/fixed of course.

That supposes that I can think of an example. Also, I don't have much control over formatting; the page you see doesn't actually have the final formatting anyway.

Push(list, any);. Appends the value to the list.

This will probably apply to all function descriptions, but perhaps indicating which argument is value and which is list would be helpful. I understand it's obvious in this situation, but even just using terms like lhs/rhs or left/right or first/second/third (consistently) would be helpful.

Also, why the semicolon? I notice other built-ins don't end with semicolons.

Referring to arguments by type makes things easier for those functions which take arguments of different types in either order.

The semicolon indicates that this is a statement, not a function.

BitwiseAnd(int, int).

BitwiseAnd(int, list). Recursively vectorises over the list.

BitwiseAnd(list, int) . Recursively vectorises over the list.

Is there a non-recursive vectorisation behaviour for some built-ins? If not, you can drop the "recursively", because the typical expectation of vectorisation is that it is recursive.

Yes, the version of Charcoal on TIO doesn't recursively vectorise some of the built-ins.

PivotLeft(int=2);. Rotates the pivot anticlockwise by 45° times the argument.

Same as with Wolfram strings. Maybe a glossary section beneath the TIO/ATO definitions would suffice.

Would it help if I called it the cursor rather then the pivot? Something like "Rotates the cursor anticlockwise by 45° times the argument, changing the default output direction."

⟲P

RotatePrism(dir=↘, literal);.

...

As RotateCopy but rotates the characters if possible.

"Same as" instead of "As" is less confusing.

Also that's really a Charcoal built-in? Wow.

"Same as but different"? Yeah, I don't think that makes sense, sorry. Would "Like" be OK?

Yes, that's really a Charcoal built-in. I've never actually used it though.

Move(:Left);. Moves the cursor one character to the left.

Print(:Left, any);. Prints the argument as if the pivot was pointing to the left.

Also used as a direction parameter to other commands.

When specifying direction parameters before, you used arrows (e.g. for ⟲P) and now you've switched to using :Direction. I'd reccomend using :Direction for everything.

This is because actually means :Left; it's just that as a command it means either Move or Print depending on whether it's followed by an expression. Perhaps I should remove the "Also used as a direction parameter to other commands" and add ":Left. Used as a direction parameter to other commands."

Ternary(any, any, any). Evaluates the second or third argument depending on whether the first argument is falsy.

It would be nice to have an explicit mention of which argument is evaluated when. Perhaps "If first is a truthy value, evaluate second. Otherwise, evaluate third".

I originally tried to write the document without using "truthy", but I failed, so I guess I can expand on this.

Random(int). Returns a random integer from 0 to (but not including) the argument. (Must be at least 1.)

Random(str). Returns a random character from the string. (Must not be empty.)

Random(list). Returns a random element from the list. (Must not be empty.)

I'm 99% sure that the "Must not be empty" applies to the input and not the result. "The argument must not be empty." would help clarify. A minor thing, I know, but it just makes things that much easier to understand, which is what you want from a reference sheet.

Would "Must not be an empty string/list" be OK?.

Minimum(str). Returns the character with the lowest ordinal. (ATO: Returns the empty string if the input was empty.)

s/ordinal/ordinal value (Unicode codepoint) (for clarity). This also applies to ceiling ()

Actually I should just not call it an ordinal and stick with Unicode codepoint.

...

Minor thing: why aren't the set of diagonal arrows grouped with the set of normal direction arrows? Seems like it'd be a better fit to organise all directions together.

The symbols are in code page order.

StringMap(int, any). Maps over the integers from 0 up to the argument and joins the results into a string.

StringMap(iter, any). Maps over the elements of the argument and joins the results into a string. (Does not work on dictionaries on TIO.)

Maps how? And is any a function? Or can it be a normal scalar/list value?

Sorry, I don't know what you're asking here, but any is any expression; it gets re-evaluated with value and index variables according to each element of the argument.

Join(str, iter). Converts the the elements of the second argument to string and joins the latter using the former. (ATO: Also converts the first argument to string.)

An excellent case-study of why using a consistent argument naming scheme is a good idea :p

That was because this had been tweaked from a previous version and as you point out it no longer makes sense.

switch (any) { case:s... (default:) }

Providing an example of how the syntax looks in SBCS mode would be helpful.

Succint mode has very little syntax. In this case it's , followed by a number of pairs of expressions and statements, followed by a final statement (if the block or program does not end at this point).

Any(int, any). Maps over the integers from 0 up to the argument and returns 0 if the given expression returns a falsy value for all of them or 1 if not. (Not available on TIO.)

Same as with StringMap - is any strictly any or does it have a specific type?

As with StringMap, any expression is allowed; it is evaluated with the given value and index variables (which is technically redundant for an integer argument) for each integer in turn until the expression evaluates to a truthy value at which point it returns 1

Σ

Sum(str). If the argument looks like a number, returns the sum of its digits, otherwise returns the sum of any embedded numbers, or 0 if there were none. (TIO: Sums absolute value of negative numbers.)

What looks like a number? Also, an example of the embedded numbers case would be good.

I think it just checks for something like -?\d+(.\d+)? but I can't remember exactly. (And again, I'm not good with examples.)

Π

Product(str). If the argument looks like a number, returns the product of its digits, otherwise returns the product of any embedded numbers, or 1 if there were none. (TIO: Takes the absolute product.)

Same as with Sum

Same as with Sum

Base(str, str). Equivalent to BaseString(str, str) but with the arguments exchanged.

Is that to say that they are swapped? I'm not quite sure if that's what "exchanged" is meaning in this context.

Right, I see "swapped" is more specific, so it works better here.

Absolute(number). Returns the norm of the number. (Does not work on complex numbers on TIO.)

How about norm/absolute value? Typically, reference sheets will simply call it "absolute value".

The function is already called Absolute and I wanted to avoid repeating myself but also show that the function works on complex numbers on ATO.

Halved(value). Division by 2. (Does not work on complex numbers and always floating-point and rounds to nearest 1e-15 on TIO, but integer divide if the original value is even on ATO.)

Why is this the circle-with-line-in-it-that-works-on-numbers built-in that gets a description, but the other 3 (increment, decrement and double) don't?

No idea. I don't feel like adding descriptions to the other three, so I'll remove this one.

§≔

AssignAtIndex(list, int, any);. Updates an element of a dictionary, or of a list (including a list of cells) using cyclic indexing.

How about "Updates an element of a dictionary or list"? Also, what do you mean by a list of cells? Do you mean "using a list as the index will update the value in first at each index in second"?

Cyclic indexing only applies to lists. Also, some of the Peek functions return lists of cells. If you AssignAtIndex to an element, it will actually update the canvas. (I do have an experimental multidimensional indexing branch where the second argument can be a list of indices (one for each dimension) where each index can be a list of indices (which then updates multiple values).)

×

Times(str, number).

Times(number, str). Repeats the string the given number of times, including fractional parts of the string, e.g. Times(1.5, "12") gives "121".

Are these two the same (barring order)? If so, I'd suggest putting the description on the first overload, rather than the second.

I did have that originally but I thought that this way I could avoid having "Same as above" on the second overload.

‖O

ReflectOverlap(dirs=→);. As ReflectOverlap but reflects around the edge characters (so that the reflected axis overlaps itself).

ReflectOverlap is defined in terms of itself. Did you mean "As ReflectCopy?

Indeed I did, thanks!

Less(number, number).

Less(str, str).

Less(list, list).

Specifying that this is "less than" would be helpful, as would be mentioning the comparison method of strings and lists.

How about "Compares using Python's < operator."

Less(number, number).

Less(str, str).

Less(list, list).

This should be whatever keyword is used for greater than. Also, the suggestion for "less than" also applies here. Don't worry, the irony is not lost on me.

Whoops, too much copy and paste... at one point all of my arrows were :Left it was that bad...

...

‖B

...

‖BO

...

The two ‖B variants were already listed in the section. Is the duplication intentional?

Yes, this is in case you look up without realising it's part of a command.

Dump();. Outputs a copy of the canvas to standard output. Delays by 10ms since the last dump. (ATO: Use --nt to disable the delay.)

How about "Has a 10 millisecond delay between calls to Dump()"?

The 10ms is calculated from the time of the last Dump();, so if the intervening code takes longer than that to run there is no further delay. (But I didn't really want to write that out in full.)

See GH.

Instead of "See GH", reference sheets I've seen typically use "Alias for GH" (not that other reference sheets have GH - they use "Alias for whatever")

It's not an alias, it's just in case you look up to see what it does without realising it's actually part of a command.

...

Now that's an interesting one. It seems to have no functionality of its own except for being a modifier for other characters. Maybe mention that instead of having a list of "see others".

Well, not instead of, because I want to show what it can modify.

Unused.

Yeah like that. That's the kind of thing I mean for .

Well, is used, just not in its own right.

See also ⟲S.

See also ⟲SO.

Why do some letters have their modifier variants listed twice, and some just have "See also"?

I don't bother with "See also" for just one line of explanation.

Trim(int);. Removes any part of the canvas outside the square with the given size, but also any part of the canvas above or to the left of the origin.

What square? Do you mean in an int x int size square centred on the origin? Where's the square?

It's, well, toplefted, on the current cursor position.

αβχδεφγηικλμνπθρστυςωξψζ

Variables. αβχφγυωψ have predefined values. ικλμνξπρςστδεζηθ are used by loop variables, if possible. (Note that expression loops consume two variables, one for the value and one for the index.) θηζεδ attempt to retrieve the first five inputs, if not being used as loop variables. (TIO: θηζεδ can only be used as loop variables.)

The brackets aren't needed because it's a sentence on its own. Also, maybe list the predefined values.

It's in brackets because it's a note. I can link to the preset values page though.