So far, whenever something needed working out, your program did it: the console sent a line of input, your program did the thinking, and printed the result. That's often the right approach. But the console can do simple calculations and make simple decisions by itself, using transient logic tags. That's useful when you want the screen to react straight away, without a round trip to your program, or when the logic belongs to the interface rather than to your program.
Each arithmetic tag takes a list of numbers in its primary field, and generates the result:
| Tag | Does | Example | Generates |
|---|---|---|---|
| add | adds them all up | <add 1,2,3> | 6 |
| sub | subtracts the rest from the first | <sub 10,3,2> | 5 |
| mul | multiplies them all | <mul 2,3,4> | 24 |
| div | divides the first by the rest | <div 7,2> | 3.5 |
| mod | the remainder after dividing | <mod 17,5> | 2 |
| neg | changes the sign | <neg 5> | -5 |
| abs | removes the sign | <abs -7> | 7 |
| int | drops anything after the point | <int 3.7> | 3 |
Dividing by zero generates inf.
add, sub, mul and div have a with field, for doing the same calculation on every element of a list:
<add 1,10,-2 with=2> <! adds 2 to each: generates 3, 12, 0 !> <mul 2,3 with=10,100> <! pairs them up: generates 20, 300 !>
With one value in with, it's applied to every element. With a list of the same length, the elements are paired up.
Whatever the user types in an input box is text, even if it looks like a number. {12} is not the
same as 12, and adding text doesn't do what you might expect: add joins text
together, so <add {5}, 1> generates 51.
The num tag converts text into a number:
<num {12}> <! generates the number 12 !>
<num { 3.5 }> <! generates 3.5; spaces around the number are ignored !>
<num {abc}> <! generates invalid: there's no number in it !>
Always convert the contents of an input box with num before calculating or comparing with it.
These tags compare values, and generate true or false:
| Tag | Generates true if... | Example |
|---|---|---|
| eq | all the values are equal | <eq 5,5,5> |
| ne | any of the values are different | <ne 1,2> |
| lt | the first is less than the second | <lt 1,2> |
| le | less than or equal | <le 2,2> |
| gt | greater than | <gt 3,2> |
| ge | greater than or equal | <ge 3,3> |
eq compares values by what they mean, using the rules from the chapter on values for
what counts as true and false. So <eq 0, false> and <eq 2, true> are
both true. Text is compared letter by letter, so <lt {apple}, {banana}> is true.
Sometimes you need to know if a value is exactly null (say), not just something that counts as false. The tags true, false, null, inf and invalid do this when you give them a value:
<null x> <! true only if x is exactly null !> <invalid <num answer>> <! true if what was typed isn't a number !>
Without a value, they just generate themselves: <null> generates null.
| Tag | Generates true if... |
|---|---|
| and | all of its values count as true |
| or | any of its values count as true |
| not | its value counts as false |
| xor | exactly one of its two values counts as true |
<and <ge age, 13>, <le age, 19>> <! true for a teenager !>
The if tag checks the condition in its primary field. If the condition counts as true, it carries out what's in its then field; otherwise, what's in its else field. Whatever the chosen branch generates, the if tag generates too:
<n:scalar 7>
<box <if <eq <mod n, 2>, 0> then={even} else={odd}>> <! the box says "odd" !>
then and else are code fields, so they can hold actions as well as values, and only the chosen branch is carried out:
<if <gt score, best> then=<best score>, <putLn {new record}>>
You can leave out else if there's nothing to do otherwise, and you can put an if inside a branch of another one.
join turns a list into a single piece of text. Its delim field says what to put between the elements:
<names:vector {Ada}, {Grace}, {Alan}>
<join names delim={, }> <! generates "Ada, Grace, Alan" !>
This is the easiest way to display a list, since the elements would otherwise run together.
split does the opposite, breaking text into a list. By default it splits wherever there are spaces; use delim to split somewhere else:
<split {red green blue}> <! generates three elements: red, green, blue !>
<split {a,b,c} delim={,}> <! generates a, b, c !>
Logic code can end up with a lot of nested angle brackets. Tag-compounding is a shorthand that helps. Instead of putting one tag inside the end of another, put a | between them:
<putLn <add 1, 2>> <! ordinary nesting !> <putLn | add 1, 2> <! the same thing, compounded !>
Everything after the | becomes a tag inside the end of the tag before it. You can compound several tags in a row, and the tag before each | can have fields of its own:
<putLn | join delim={-} | add 1,2 with=10> <! sends "11-12" !>
Compounding is especially neat for changing a value based on itself. This adds one to count:
<count | add count, 1> <! the same as <count <add count, 1>> !>
This program contains three small tools that all work inside the console. Apart from waiting at the end, the program does nothing at all:
print('''
<count:scalar 0>
<button {Click me} onClick=<count | add count, 1>, <shown count>>
Clicks: <shown:span bold=true {0}></p>
<a:input width=4,em {0}> and <b:input width=4,em {0}></n>
<button {+} onClick=<result | add <num a>, <num b>>>
<button {-} onClick=<result | sub <num a>, <num b>>>
<button {x} onClick=<result | mul <num a>, <num b>>>
<button {/} onClick=<result | div <num a>, <num b>>>
= <result:span bold=true {0}></p>
What is 6 x 7? <answer:input width=4,em>
<button {Check} onClick=<feedback | if <eq <num answer>, 42>
then={Correct!} else={Try again.}>>
<feedback:span {}>
''')
input()
Clicks: 3Now that the console can do logic, where should your logic go? A good rule:
<inf ...>.)