Edit

kc3-lang/kc3/doc/3_Guides/3.5_Tutorial.en.md

Branch :

  • doc/3_Guides/3.5_Tutorial.en.md
  • # KC3 tutorial and examples
    
    Here are a few `ikc3` examples to play with.
    
    
    ## Maps
    
    KC3 maps are key-value stores, you can use any tag as a key and
    associate a value to it.
    
    You can use destructuring to access KC3 maps :
    ```elixir
    ikc3> a = %{id: 1, title: "My title", message: "Hello, world !"}
    %{id: 1, title: "My title", message: "Hello, world !"}
    ikc3> a = %{}
    %{id: 1, title: "My title", message: "Hello, world !"}
    ikc3> %{id: id, title: "My title", message: message} = a
    %{id: 1, title: "My title", message: "Hello, world !"}
    ikc3> id
    1
    ikc3> message
    "Hello, world !"
    ```
    
    You can use the dot syntax to access map values from a `Sym` key :
    ```elixir
    ikc3> a = %{id: 1, title: "My title", message: "Hello, world !"}
    %{id: 1, title: "My title", message: "Hello, world !"}
    ikc3> a.id
    1
    ikc3> a.message
    "Hello, world !"
    ```
    
    You can also use the `KC3.access` function for the same result :
    ```elixir
    ikc3> a = %{id: 1, title: "My title", message: "Hello, world !"}
    %{id: 1, title: "My title", message: "Hello, world !"}
    ikc3> access(a, :id)
    1
    ikc3> access(a, :message)
    "Hello, world !"
    ```
    
    
    ## Unicode characters
    
    `ikc3` fully supports Unicode :
    
    Some unicode characters :
    ```elixir
    ikc3> '\U+1B2FB'
    '𛋻'
    ikc3> '𐅀'
    '𐅀'
    ikc3> '🤩'
    '🤩'
    ikc3>
    ```
    
    ## Large integers
    
    ```elixir
    ikc3> a = 1 + 100000000000000000000000000000000
    100000000000000000000000000000001
    ikc3> a * a
    10000000000000000000000000000000200000000000000000000000000000001
    ikc3>
    ```
    
    ## Ratios
    
    Ratios are made with a couple of large integers : the numerator
    which can be any number, and the denominator which has to be positive.
    They represent fractions of integral numbers.
    They are written with a slash and no space.
    
    ```elixir
    ikc3> 1/2 + 2/3
    7/6
    ikc3> 1/2 * 2/3
    1/3
    ikc3> 1/2 / 2/3
    3/4
    ikc3> 1/2 - 2/3
    -1/6
    ```
    
    
    ## Complex numbers
    
    Complex numbers are constructed using the operator `+i` on any kind of
    numbers (unsigned, signed, float, ratios, and even other complex
    numbers). For instance, you can write `a +i b` where `a` and `b` are
    real numbers.
    
    ```elixir
    ikc3> 1 +i 2
    1 +i 2
    ikc3> 1 +i 2 + 2 +i 3
    3 +i 5
    ikc3> (1 +i 2) * (2 +i 3)
    -4 +i 7
    ikc3> (1 +i 2) / (2 +i 3)
    0 +i 0
    ikc3> (1/1 +i 2/1) / (2 +i 3)
    8/13 +i 1/13
    ```
    
    As you can see integer division is not producing ratios.
    That might change in future releases.
    
    
    ## Lists
    
    Lists are marked with brackets `[]`.
    
    Regular lists can be :
     - an element and a list : `[1 | []]` → `[1]`
     - multiple elements : `[1, 2, 3]`
     - multiple elements and a list : `[1, 2 | [3, 4]]` → `[1, 2, 3, 4]`
     - the empty list : `[]`
    
    Regular lists end with the empty list : `[1] == [1 | []]`.
    
    You can also contruct dotted lists like in Common Lisp where
    the next list pointer is an arbitrary form. E.g. :
     - an element and an element : `[1 | 2]`
     - multiple elements and an element : `[1, 2, 3 | 4]`
     - the empty list and an element : `[[] | 1]`
    
    All these list formats are supported in pattern matching.
    
    
    ## Pattern matching and destructuring
    
    The KC3 pattern matching principles come from Erlang and Elixir.
    
    All tag data structures in KC3 can be pattern matched using the equal
    sign (`=`) against litteral values containing identifiers. All
    identifiers are supposed to be new bindings when using pattern matching
    in KC3. If you want to use an identifier's value in pattern matching you
    must use the _pin operator_ (`^`). Variables can be assigned a new value
    from either side of the equal sign and from inside a tag data structure,
    which is called _destructuring_.
    
    
    Examples :
    ```elixir
    ikc3> a = 1
    1
    ikc3> a = 2
    2
    ikc3> a
    2
    ikc3> ^ a = 1
    void
    ikc3> ^ a = 2
    2
    ikc3> ^ a = b
    2
    ikc3> b
    2
    ```
    
    To use destructuring just type the litteral value you want to match and
    put identifiers (variable names) where you want a variable matching the
    value on the other side of the equal sign. This is the most visual
    approach possible to text-based value matching : the data is constantly
    matched to litterals that show their type to the programmer. This is
    really helpful when writing large programs that need to scale in the way
    of abstractions. Let the data flow in the code through visual types.
    
    Examples :
    ```elixir
    ikc3> [x, y | z] = List.reverse([1, 2, 3, 4])
    [4, 3, 2, 1]
    ikc3> x
    4
    ikc3> y
    3
    ikc3> z
    [2, 1]
    ```
    
    
    ## Macros
    
    KC3 macros are like Common Lisp macros with Elixir pattern-matching.
    
    Macros are like functions but start with `macro` instead of `fn` and
    their arguments do not get evaluated. However they get pattern matched
    and the full power of the pattern matcher is available for arguments
    destructuring. Use a map if you want named arguments. Use a list if you
    want &rest arguments, use a block if you want a &body argument.
    
    When evaluated, a macro call returns a tag which is in turn evaluated
    in the calling site lexical environment. This allows for DSLs and custom
    control structures to be defined in KC3.
    
    Many basic operations in KC3 are defined as macros : error handling,
    free operations with `unwind-protect`, graph database operations like
    `Facts.with`.
    
    
    ## If, then, else.
    
    Conditionals in KC3 are like in Ruby, for example :
    ```elixir
    ikc3> if true && true
    ikc3>   1 + 1
    ikc3>   2 + 2
    ikc3> end
    4
    
    ikc3> if true && false
    ikc3>   1 + 1
    ikc3>   2 + 2
    ikc3> else
    ikc3>   3 + 3
    ikc3>   4 + 4
    ikc3> end
    8
    ```
    
    A KC3 `if` statement always return a value. If the condition is true, the
    first (then) block gets evaluated. If the condition is false the second
    block gets evaluated. If the condition is false and an `else` block is
    not provided, then `void` gets returned.
    
    One liner examples with `then` :
    ```elixir
    ikc3> if 42 then 100 else 101 end
    100
    ikc3> if 0 then 100 else 101 end
    101
    ```
    
    ## defmodule and def
    
    Example :
    ```elixir
    ikc3> defmodule Example do
    ikc3>   def three = 3
    ikc3>   def double = fn (x) do x * 2 end
    ikc3>   def double_tuple = macro (x) do {x, x} end
    ikc3>   def operator_double = %KC3.Operator{sym: :double, symbol_value: fn (x) { x * 2 }
    ikc3> end
    Example
    ikc3> Example.three
    3
    ikc3> Example.double
    fn (x) do x * 2 end
    ikc3> Example.double(21)
    42
    ikc3> Example.double_tuple(:ok)
    {:ok, :ok}
    ikc3> double 21
    42
    ```
    
    
    ## Facts
    
    The Facts module allows read and write access to a graph database
    containing facts : triples of subject, predicate, object.
    
    Examples for querying the KC3 database containing all definitions of
    the interpreter :
    
    ```elixir
    ikc3> Facts.with_tags(Facts.env_facts(), KC3, :operator, ?,
            fn (fact) { puts(fact.object); :ok })
    operator_eq
    operator_gt
    operator_lt
    [...]
    :ok
    ```
    
    ---
    
    Top : [KC3 Guides](./)
    
    Previous : [KC3 Structure Guide](3.4_Structure)