# 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]
```