# Quick Tour The documentation below `syntax` is written with the aim of being understandable even for programming beginners. For those who have already mastered languages ​​such as Python, Rust, Haskell, etc., it may be a bit verbose. So, here's an overview of the Erg grammar. Please think that the parts not mentioned are the same as Python. ## variables, constants Variables are defined with `=`. As with Haskell, variables once defined cannot be changed. However, it can be shadowed in another scope. ```python i = 0 if True: i = 1 assert i == 0 ``` Anything starting with an uppercase letter is a constant. Only things that can be computed at compile time can be constants. Also, a constant is identical in all scopes since its definition. ```python PI = 3.141592653589793 match random.random!(0..10): PIs: log "You get PI, it's a miracle!" ``` ## declaration Unlike Python, only the variable type can be declared first. Of course, the declared type and the type of the object actually assigned to must be compatible. ```python i: Int i = 10 ``` ## Functions You can define it just like in Haskell. ```python fib0 = 0 fib1 = 1 fibn = fib(n - 1) + fib(n - 2) ``` An anonymous function can be defined like this: ```python i -> i + 1 assert [1, 2, 3].map(i -> i + 1).to_arr() == [2, 3, 4] ``` ## operator The Erg-specific operators are: ### mutating operator (!) It's like `ref` in Ocaml. ```python i = !0 i.update! x -> x + 1 assert i == 1 ``` ## procedures Subroutines with side effects are called procedures and are marked with `!`. ```python print! 1 # 1 ``` ## generic function (polycorrelation) ```python id|T|(x: T): T = x id(1): Int id("a"): Str ``` ## Records You can use the equivalent of records in ML-like languages ​​(or object literals in JS). ```python p = {x = 1; y = 2} ``` ## Ownership Ergs are owned by mutable objects (objects mutated with the `!` operator) and cannot be rewritten from multiple places. ```python i = !0 j = i assert j == 0 i#MoveError ``` Immutable objects, on the other hand, can be referenced from multiple places. ## Visibility Prefixing a variable with `.` makes it a public variable and allows it to be referenced from external modules. ```python # foo.er .x = 1 y = 1 ``` ```python foo = import "foo" assert foo.x == 1 foo.y # VisibilityError ``` ## pattern matching ### variable pattern ```python # basic assignments i = 1 # with type i: Int = 1 # functions fn x = x + 1 fn: Int -> Int = x -> x + 1 ``` ### Literal patterns ```python # if `i` cannot be determined to be 1 at compile time, TypeError occurs. # shorthand of `_: {1} = i` 1 = i # simple pattern matching match x: 1 -> "1" 2 -> "2" _ -> "other" # fibonacci function fib0 = 0 fib1 = 1 fibn: Nat = fibn-1 + fibn-2 ``` ### constant pattern ```python PI = 3.141592653589793 E = 2.718281828459045 num = PI name = match num: PI -> "pi" E -> "e" _ -> "unnamed" ``` ### discard (wildcard) pattern ```python _ = 1 _: Int = 1 right(_, r) = r ``` ### Variable length patterns Used in combination with the tuple/array/record pattern described later. ```python [i,...j] = [1, 2, 3, 4] assert j == [2, 3, 4] first|T|(fst: T, ...rest: T) = fst assert first(1, 2, 3) == 1 ``` ### Tuple pattern ```python (i, j) = (1, 2) ((k, l), _) = ((1, 2), (3, 4)) # If not nested, () can be omitted (1, 2 are treated as (1, 2)) m, n = 1, 2 ``` ### array pattern ```python length[] = 0 length[_, ...rest] = 1 + lengthrest ``` #### record pattern ```python {sin; cos; tan; ...} = import "math" {*} = import "math" # import all person = {name = "John Smith"; age = 20} age = match person: {name = "Alice"; _} -> 7 {_; age} -> age ``` ### Data class pattern ```python Point = Inherit {x = Int; y = Int} p = Point::{x = 1; y = 2} Point::{x; y} = p ``` ## Comprehensions ```python odds = [i | i <- 1..100; i % 2 == 0] ``` ## class Erg does not support multiple/multilevel inheritance. ## Traits They are similar to Rust traits, but in a more literal sense, allowing composition and decoupling, and treating attributes and methods as equals. Also, it does not involve implementation. ```python XY = Trait {x = Int; y = Int} Z = Trait {z = Int} XYZ = XY and Z Show = Trait {show: Self.() -> Str} @Impl XYZ, Show Point = Class {x = Int; y = Int; z = Int} Point. ... ``` ## patch You can give implementations to classes and traits. ## Sieve type A predicate expression can be type-restricted. ```python Nat = {I: Int | I >= 0} ``` ## parametric type with value (dependent type) ```python a: [Int; 3] b: [Int; 4] a + b: [Int; 7] ```