Types¶
Symbolic provides a numeric hierarchy built on arbitrary-precision arithmetic, a Unicode string type, ordered and unordered collection types, and an optional gradual type-annotation system.
Numeric Types¶
All numeric types derive from Number, which provides arithmetic,
comparison, trigonometric, and algebraic operations uniformly across the
hierarchy.
Integer¶
Arbitrary-precision integers. Division of two integers returns a Fraction,
not a truncated integer:
a = 42
b = -17
c = 10 ^ 100 # arbitrarily large
d = 0xFF # hexadecimal literal
e = 0b1010_1111 # binary literal with separator
print(a + b) # 25
print(10 / 3) # 10/3 (Fraction, not 3)
print(10 // 3) # 3 (floor division returns Integer)
Float¶
Arbitrary-precision floating-point numbers backed by mpmath.mpf. The
working precision defaults to 15 significant digits and adapts to the
precision of the literal:
x = 3.14159265358979
y = 6.022e23
z = 1.5e-10
# Precision-controlled block
@$precision 50 {
result = x ^ 2;
}
Fraction¶
Exact rational numbers. Created automatically by integer division and maintained in lowest terms:
r = 10 / 3 # 10/3
s = 1 / 2 + 1/3 # 5/6
print(r.numerator) # 10
print(r.denominator) # 3
Complex¶
Arbitrary-precision complex numbers using mpmath.mpc. The imaginary
unit is i:
z1 = 3 + 4i
z2 = 2.5 - 1.7i
z3 = 1i # pure imaginary
print(|z1|) # 5.0 — magnitude using pipe-absolute syntax
print(z1*) # 3-4i — complex conjugate (postfix complement)
print(z1.real) # 3
print(z1.imag) # 4
Uncertainty Propagation¶
Numeric values can carry an uncertainty. Arithmetic on uncertain values automatically propagates error in quadrature:
# Not yet user-facing syntax — set via .set_uncertainty()
x = Float(9.81)
x.set_uncertainty(0.02)
print(x.format()) # "9.81 ± 0.02"
Boolean¶
The Boolean type wraps true and false. Booleans behave as integers
(true = 1, false = 0) in arithmetic contexts:
a = true
b = false
print(a and b) # false
print(a or b) # true
print(!a) # false
print(a + 1) # 2
String¶
Strings are UTF-8 Unicode sequences. The String type extends Python’s
str and provides functional methods:
s = "Hello, World!"
print(s.length) # 13
print(s.upper()) # "HELLO, WORLD!"
print(s.reverse()) # "!dlroW ,olleH"
print(s.contains("World"))# true
print(s.split(", ")) # ["Hello", "World!"]
print(s[0..5]) # "Hello"
# Functional transformations
digits = "a1b2c3"
nums = digits.filter((c) -> c >= "0" and c <= "9")
print(nums) # "123"
# Palindrome check
print("racecar".is_palindrome()) # true
Collections¶
List ~~~
Ordered, mutable, heterogeneous sequences:
nums = [1, 2, 3, 4, 5]
nums.append(6)
nums.reverse()
print(nums) # [6, 5, 4, 3, 2, 1]
# Functional pipeline — lazy evaluation, collect to materialize
result = nums
.filter((x) -> x > 2)
.map((x) -> x ^ 2)
.to_list()
# Reduce
total = nums.reduce((a, b) -> a + b)
# Slicing
sub = nums[1..3] # [5, 4]
# Fill constructor
zeros = [].fill(0, 10) # [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
Tuple¶
Ordered, immutable sequences. A trailing comma distinguishes a single-element tuple from a parenthesized expression:
t = (1, "hello", 3.14)
(x, y, z) = t # destructuring assignment
singleton = (42,) # single-element tuple
empty = ()
Dictionary¶
Key-value maps with functional accessors:
d = {"name": "Alice", "score": 97}
print(d["name"]) # "Alice"
print(d.get("age", 0)) # 0 (default)
d["rank"] = 1
# Functional transforms
upper_keys = d.map_keys((k) -> k.upper())
high = d.filter_items((k, v) -> v > 50)
Set ~~
Unordered collections of unique elements:
s1 = {1, 2, 3}
s2 = {2, 3, 4}
print(s1.union(s2)) # {1, 2, 3, 4}
print(s1.intersection(s2)) # {2, 3}
print(s1.difference(s2)) # {1}
Type Annotations¶
Type annotations are optional. When present, they are written after a colon on function parameters and with an arrow for return types. Annotations are evaluated at definition time; the runtime does not enforce them by default unless contract clauses are present.
fn greet(name: String) -> String {
return f"Hello, {name}!";
}
fn divide(a: Integer, b: Integer) -> Fraction
requires b != 0 {
return a / b;
}
Union types use ||:
fn process(value: Integer || Float || Complex) -> Float || Complex {
return value.sqrt();
}
Generic parameters use angle brackets:
fn identity<T>(x: T) -> T {
return x;
}
Constants¶
The const modifier prevents reassignment. const values are also
implicitly final (cannot be shadowed in a nested scope):
const MAX_RETRIES = 5
const BASE_URL = "https://api.example.com"
MAX_RETRIES = 6 # compile error: assignment to constant
Null and Optional Values¶
Symbolic does not have a dedicated null literal. The null-coalesce operator
?? and optional-chaining operator ?. support nullable patterns:
value = lookup("key") ?? "default"
length = user?.profile?.bio?.length ?? 0
See also
<no title> — Type annotations on parameters and return types.
<no title> — Type patterns in match expressions.