Naming Conventions
Epsil spells the standard library in lowercase: sin, map,
isPrime, pi. Every function and constant of the library also answers to
its MathJSON name, with an initial capital: Sin, Map, IsPrime, Pi.
The two spellings name the same thing.
sin(pi / 2)
// ➔ 1
Sin(Pi / 2)
// ➔ 1
map(sin, [0, pi / 2])
// ➔ [0, 1]
The lowercase spelling is the style of the language, and it is the
spelling Epsil writes: the serializer (serializeEpsil), the format
command, the --epsil output mode and the snippet a diagnostic quotes all
write a library name in lowercase (sin(x), map(sin, xs), pi). A
program that binds the lowercase spelling itself (let sin = 3, a
parameter named pi) is written with the capitalized name for that
library member, so the text reads back as the same program. The
capitalized spelling is what MathJSON uses, and what an engine error names.
How the spelling is formed
The lowercase spelling of a library name lowercases its first letter:
Floor is floor, IsPrime is isPrime, StringJoin is stringJoin,
GoldenRatio is goldenRatio. When the name starts with several capital
letters, the whole run is lowercased and the last letter of the run stays a
capital when it starts the next word: GCD is gcd, LCM is lcm,
LUDecomposition is luDecomposition, NDSolve is ndSolve.
The Standard Library page lists both spellings of every definition.
Names with no lowercase spelling
A library name has no lowercase spelling when Epsil already has a way to write it:
- Operators the language writes as symbols:
Addis+,Poweris^,Pipeis|>,Equalis==,Andis&&,Elementisin,Rangeis.., and so on for the whole operator table. - Constructs with their own syntax:
IfandWhichareif/else,Matchismatch,Loopisforandwhile,Functionis=>andfunction,Declareisletandconst,Blockis{ … },Typedisx: T,Spreadis...xs,Atisxs[i]. - Literals:
Listis[…],Tupleis(a, b),Setis{…},Dictionaryis{k: v},Stringis"…",TrueandFalsearetrueandfalse,NaNandInfinityare literal words. - Single-letter names:
DandNstay capitalized, becausedandnare ordinary variable names. - Relation glyphs with no reading as a function (
Approx,Tilde,Precedes,PlusMinus, …): write them through a LaTeX island. - Engine-internal heads that a program never writes (
ErrorCode,RuntimeError,Signature, …).
Writing one of these in lowercase is an unknown call, reported with a did-you-mean suggestion when a close name exists.
User names and shadowing
User-defined variables, functions, and types are lowercase too: total,
area, type point = …. Nothing in the parser or the engine enforces a
case; the library spellings and the user names share one namespace and
resolve by scope, not by case.
A user binding shadows a library name for the rest of its scope, whichever
spelling the library name has: a let, a const, a parameter, a loop
variable, a match pattern, or a function definition.
let sum = 0
sum + 1
// ➔ 1
function mean(x) { 42 }
mean(7)
// ➔ 42
[1, 2, 3] |> map(count => count * 2)
// ➔ [2, 4, 6]
A bare library name that nothing shadows IS the library definition, in
every position: mean alone is the Mean function, so mean + 1 is a type
error rather than a sum with an unknown number. Declare the variable first.
let mean = 5
mean + 1
// ➔ 6
The constants e and i are lowercase library values already: e^2 is
the exponential, i^2 is -1, and 1 + 2i is a complex number. They
shadow like any other name — let e = 3; e^2 is 9.
The capitalized spelling shadows the same way: let Pi = 3 makes Pi the
number 3 for the rest of its scope, and function Square(x) { x + 100 }
makes Square(3) call that function. Shadowing a name that an operator
builds changes the operator too: + is Add, so a user Add is what +
calls in its scope, and a definition such as function Add(x, y) { x + y }
calls itself without end. Compiled code does not use a shadowed library
operator: the call is interpreted instead.
The absence markers Nothing, Missing and Undefined are the exception:
they cannot be rebound, and a binding of one of them is an error
(absence-marker-binding). The engine recognizes them by their name — it
drops Nothing from an argument list and reads a Missing operand as
absent — so a binding could never behave like the value it holds. In a
match, test for a marker with == Missing: a bare Missing there would
be a new variable.
To name a raw symbol that happens to spell a library name, use the verbatim
form: `sin` is the symbol sin, not the sine function.
Glyph Aliases
A few mathematical glyphs are input aliases for library symbols,
canonicalized at the lexer — every position (expression, parameter,
binding, match pattern) treats the glyph exactly like its ASCII spelling,
and serialization writes the library spelling (pi for π):
| Glyph | Symbol |
|---|---|
π | Pi |
∞ | Infinity |
ⅈ | ImaginaryUnit |
ⅇ | ExponentialE |
∅ | EmptySet |
⧝ | ComplexInfinity |
ℝ | RealNumbers |
ℤ | Integers |
ℚ | RationalNumbers |
ℕ | NonNegativeIntegers |
ℂ | ComplexNumbers |
∫ | Integrate |
∑ | Sum |
∏ | Product |
3.1 ∈ ℝ
// ➔ True
∫(1/x, x)
// ➔ Integrate(1/x, x)
Note the doublestruck ⅈ/ⅇ (U+2148/U+2147), not the ordinary letters:
i and e are the lowercase library constants described above. To name a
raw symbol that happens to be a glyph, use the verbatim form (`π`).
In a type annotation the number-set glyphs name the type, not the set
constant: c: ℝ is c: real, n: ℕ is n: integer<0..>. See
Types.
Subscripts
A run of subscript letters and digits directly after a name is part of the
name, spelled with an underscore — the same name the LaTeX x_n produces:
| Written | Symbol |
|---|---|
xₙ | x_n |
a₁ | a_1 |
a₁₂ | a_12 |
xᵢⱼ | x_ij |
So xₙ can be declared, assigned, matched and passed exactly like x_n,
and let xₙ = 3 followed by x_n reads the same binding. A subscript that
holds a sign or a parenthesis is not a name: xₖ₊₁ is the expression
Subscript(x, k + 1). Superscripts never join a name — x² is x^2; see
Superscripts and subscripts.