operator - pannous/warp GitHub Wiki

Functions group externally square 1 + 2 == square(1 + 2) VS √4+5=√(4)+5 Operators group tighter than functions

Functions expect their arguments on the right hand side
Suffix operators expect their arguments on the left-hand side e.g. ²=square x²
Infix operators expect their arguments on both side: x+y x*y ...
Prefix operators expect their arguments on the right-hand side -x, ++x, !x, ½x
Circumfix operators are such as (...) {...} "..." are all built in and not overwritable todo
N-ary operators are currently not supported ( x = 5 % 7 todo: because they can be rewritten x%7==5 ? )

General N-ary operators are currently not supported ( e.g. mathematical equals-with-respect-to x == y % z todo: because they can be rewritten x%z==y%z ? ) Special hardwired ternary operators: array#position=value, list[index]=value, data[pattern]=value, condition?then:else The first cases can be handled via references

UTF symbols and their english aliases are almost completely identical when parsing and evaluating 1 + 2 == 1 plus 2 == 1 add 2

goals

Operators follow an alias hierarchy, so a & b will try to invoke et, and, add and may even fallback to plus combine concat, or let the compiler suggest such fallbacks if the functions are not implemented on the object.

List of operators and their variants (see aliases.wasp). Planned: the words that do not work yet: et, subtract, mul, multiply, equal, more, bigger, less, smaller, to-the, ^| (card operator-word-aliases); increase, decrease, divide … by (card mutation-phrases); nr and the ordinals 1st 2nd … (card ordinal-index-words).

* et &
* and && ⋀ ∧
* or || ⋁ ∨ 
* xor ^| ⊻
* not ! ¬
* add +
* plus +
* minus subtract sub -
* times mul * × ⋅ multiply
* div / ÷
* mod modulo %
* equal equals ≟ == ≡ ﹦ 
* approximately circa ≈ ⋍ : numbers within 1e-9 relative (`tolerance`) or 1e-12 absolute near zero (`sin(π) ≈ 0`), texts ignoring case and accents
* similar ~ ~~ : looser, numbers within 1% (`rough_tolerance`), texts also ignoring surrounding whitespace and punctuation: `"Hello!" ~ "hello"`.
  A class's `approximately` or `similar` method, if it defines only one, serves both
* more bigger >
* less smaller <
* exp / to the power ^ ↑ : `2↑3` is 8
* log to a base ↓ ⌟ : `8↓2` is 3, log base 2 of 8; `b⌞x` puts the base first.
  `log(1000, 10)` is exactly 3 (bases 10 and 2 use log10 and log2); `log([1 100], 10)` is `[0 2]`
  ↑ and ↓ are typed infix operators of numbers (lib/prelude.warp); another type overloads them beside the numbers:
  `infix operator ↑(v: V, n: int) := V(v.x * n)`
* square_root √ sqrt
* increase ++ 
* increase … by  +=
* decrease --
* decrease … by  -=
* divide … by  /=
* to … / … be :=  
* to-the ^
* be :=
* is := or == or instance
* then pipe |
* of in @
* 's with .
* that / with / which / filter []
* index nr 1st 2nd 3rd 4th nth _th #
* xor ⊻ ^|
* nand ¬& ⊼ : not (a and b)
* is not : not (a is b), `3 is not 4` is true
* and= &&=
* or= ||=

Caution: ^ in Angle is power “to the”, xor is ^| ⊻

Right associative operators

Most operators group from the left: 8 - 4 - 2 is (8 - 4) - 2. These group from the right:

2^3^2          // 512, 2^(3^2), as in mathematics
a = b = 3      // a = (b = 3), also :=
a ?? b ?? c    // a ?? (b ?? c)
x ? y : z ? w : v
int -> int -> int   // int -> (int -> int)
b of a of x    // b of (a of x), the reverse of x.a.b

of reads like English: “the length of the names of the people” is length of (names of (people)), while the possessive reads the other way round, as . does: “the people's names' length”. English lets a describing of attach further left (“the Prince of Wales of 1900”, “a picture of the president of great value”); in warp such a fixed name is one identifier and a description is a field or filter, and (a of b) of c groups from the left explicitly. in chains the same way after a selector word (chars, characters, letters, words, lines, keys, values): length of characters in "hello" is 5. Elsewhere x in xs stays membership. A plural field reads the field of every item of a list: names of people and people.names give each person's name.

& and |

Of two whole numbers, & and | combine the bits; of truth values they are the logical and and or:

12 & 10       // 8
12 | 10       // 14
yes & no      // no, with the hint "prefer and over &"
12 and 10     // 10

and, or, && and || stay logical on numbers. As an if or while condition the bits warn, since if 8 & 4 is false: write 8 and 4 for the logical and, or (8 & 4) != 0 for the bits. In a match arm | separates alternatives, and between a value and a function it is the pipe.

Keywords that resolve to operators depending on context:

is in of to from sub super

The '=' operator is context sensitive: usually it acts as assignment like :=, in conditions it acts as comparison like

Operators are usually pure meaning that they are side effects free and do not use global information.

Operators can be self modifying, such as ++, += and << as in

cout << "Hello" << " " << "world!" << endl;

control flow keywords

if then else otherwise once when times try catch except while until unless

Infix operators

Infix operators in Angle (as in Julia) are simply functions that can be used with an alternative syntax.

A word can be an infix operator too, its operands named as a function's parameters:

infix operator divides(d:int, n:int) := n % d == 0
3 divides 12    // yes
5 divides 12    // no

divides(3, 12) is the call form. operator divides(d:int, n:int) := … without a kind is the same infix operator. Without parameters the operands are left and right: infix operator times := left * right. A declared operator binds like + and is known in the whole file. infix divides(d, n) := … works too, with a note naming infix operator divides.

A free Unicode symbol nothing defines is a name too, so a program can give it a meaning, here "if and only if":

infix operator ⇔(a: bool, b: bool) := a == b
(1 > 0) ⇔ (2 > 0)    // yes

Used undefined, it says how: operator ⇔ is not defined (define it with infix operator ⇔(a, b) := …).

Operator overloading

The behavior of operators can be documented or changed by declaring either the symbol or the name to add a tree to an image: paint tree on image
tree + image := paint tree on image

All Operators automatically receive a self modifying variant: x ⊛= b is always a shorthand for x = x ⊛ b for all custom operators (⊛ here being a wildcard placeholder).

Introducing a new operator changes the lexical specification of the language, which changes the lexical analysis. The arity and precedence of the operator is then part of the phrase syntax of the language, which changes the phrase-level analysis. For example, adding an operator @ requires lexing and tokenizing this character, and the phrase structure ( syntax tree) depends on the arity and precedence of this operator.

Functions group externally: square 1 + 2 == square(1 + 2) VS √4+5=√(4)+5 Operators group tighter than functions

prefix operator ⁻ := it*-1
suffix operator ⁰ := 1
suffix operator ³ := it*it*it

Note that suffix operators correspond to (prefix) functions:

# x stands for any variable
x² = square x 

Note that suffix operators correspond to (suffix) language concious functions:

x² = x squared

squared is recognized as grammatical form of the 'square' function.

This simple pattern to allow adding -d or -ed holds for all functions:

verb x == x verbed

See k programming language https://estradajke.github.io/k9-simples/k9/index.html https://news.ycombinator.com/item?id=28493283

superscript signs bind higher! x²⁺³ == x⁵