Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 11 additions & 11 deletions lib/elixir/pages/getting-started/basic-types.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ iex> 10 / 2
5.0
```

Notice that `10 / 2` returned a float `5.0` instead of an integer `5`. This is expected. In Elixir, the operator `/` always returns a float. If you want to do integer division or get the division remainder, you can invoke the `div` and `rem` functions:
Notice that `10 / 2` returned a float `5.0` instead of an integer `5`. This is expected. In Elixir, the operator [`/`](`//2`) always returns a float. If you want to do integer division or get the division remainder, you can invoke the [`div`](`div/2`) and [`rem`](`rem/2`) functions:

```elixir
iex> div(10, 2)
Expand Down Expand Up @@ -61,7 +61,7 @@ iex> 1.0e-10

Floats in Elixir are 64-bit precision.

You can invoke the `round` function to get the closest integer to a given float, or the `trunc` function to get the integer part of a float.
You can invoke the [`round`](`round/1`) function to get the closest integer to a given float, or the [`trunc`](`trunc/1`) function to get the integer part of a float.

```elixir
iex> round(3.58)
Expand All @@ -70,7 +70,7 @@ iex> trunc(3.58)
3
```

Finally, we work with different data types, we will learn Elixir provides several predicate functions to check for the type of a value. For example, the `is_integer` can be used to check if a value is an integer or not:
Finally, we work with different data types, we will learn Elixir provides several predicate functions to check for the type of a value. For example, [`is_integer`](`is_integer/1`) can be used to check if a value is an integer or not:

```elixir
iex> is_integer(1)
Expand All @@ -79,7 +79,7 @@ iex> is_integer(2.0)
false
```

You can also use `is_float` or `is_number` to check, respectively, if an argument is a float, or either an integer or float.
You can also use [`is_float`](`is_float/1`) or [`is_number`](`is_number/1`) to check, respectively, if an argument is a float, or either an integer or float.

## Identifying functions and documentation

Expand Down Expand Up @@ -118,7 +118,7 @@ iex> true == false
false
```

Elixir also provides three boolean operators: `or/2`, `and/2`, and `not/1`. These operators are strict in the sense that they expect something that evaluates to a boolean (`true` or `false`) as their first argument:
Elixir also provides three boolean operators: [`or`](`or/2`), [`and`](`and/2`), and [`not`](`not/1`). These operators are strict in the sense that they expect something that evaluates to a boolean (`true` or `false`) as their first argument:

```elixir
iex> true and true
Expand Down Expand Up @@ -219,7 +219,7 @@ iex> "hellö"

> Note: if you are running on Windows, there is a chance your terminal does not use UTF-8 by default. You can change the encoding of your current session by running `chcp 65001` before entering IEx.

You can concatenate two strings with the `<>/2` operator:
You can concatenate two strings with the [`<>`](`<>/2`) operator:

```elixir
iex> "hello " <> "world!"
Expand Down Expand Up @@ -252,7 +252,7 @@ iex> "hello\nworld"
"hello\nworld"
```

You can print a string using the `IO.puts/1` function from the `IO` module:
You can print a string using the [`IO.puts`](`IO.puts/1`) function from the `IO` module:

```elixir
iex> IO.puts("hello\nworld")
Expand All @@ -261,7 +261,7 @@ world
:ok
```

Notice that the `IO.puts/1` function returns the atom `:ok` after printing.
Notice that the [`IO.puts`](`IO.puts/1`) function returns the atom `:ok` after printing.

Strings in Elixir are represented internally by contiguous sequences of bytes known as binaries:

Expand All @@ -277,7 +277,7 @@ iex> byte_size("hellö")
6
```

Notice that the number of bytes in that string is 6, even though it has 5 graphemes. That's because the grapheme "ö" takes 2 bytes to be represented in UTF-8. We can get the actual length of the string, based on the number of graphemes, by using the `String.length/1` function:
Notice that the number of bytes in that string is 6, even though it has 5 graphemes. That's because the grapheme "ö" takes 2 bytes to be represented in UTF-8. We can get the actual length of the string, based on the number of graphemes, by using the [`String.length`](`String.length/1`) function:

```elixir
iex> String.length("hellö")
Expand All @@ -293,7 +293,7 @@ iex> String.upcase("hellö")

## Structural comparison

Elixir also provides `==`, `!=`, `<=`, `>=`, `<` and `>` as comparison operators. We can compare numbers:
Elixir also provides [`==`](`==/2`), [`!=`](`!=/2`), [`<=`](`<=/2`), [`>=`](`>=/2`), [`<`](`</2`) and [`>`](`>/2`) as comparison operators. We can compare numbers:

```elixir
iex> 1 == 1
Expand Down Expand Up @@ -322,7 +322,7 @@ iex> 1 == 2.0
false
```

However, you can use the strict comparison operator `===` and `!==` if you want to distinguish between integers and floats (that's the only difference between these operators):
However, you can use the strict comparison operator [`===`](`===/2`) and [`!==`](`!==/2`) if you want to distinguish between integers and floats (that's the only difference between these operators):

```elixir
iex> 1 === 1.0
Expand Down
26 changes: 13 additions & 13 deletions lib/elixir/pages/getting-started/case-cond-and-if.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
# case, cond, and if

In this chapter, we will learn about the `case`, `cond`, and `if` control flow structures.
In this chapter, we will learn about the [`case`](`case/2`), [`cond`](`cond/1`), and [`if`](`if/2`) control flow structures.

## case

`case` allows us to compare a value against many patterns until we find a matching one:
[`case`](`case/2`) allows us to compare a value against many patterns until we find a matching one:

```elixir
iex> case {1, 2, 3} do
Expand All @@ -18,7 +18,7 @@ iex> case {1, 2, 3} do
"This clause will match and bind x to 2 in this clause"
```

If you want to pattern match against an existing variable, you need to use the `^` operator:
If you want to pattern match against an existing variable, you need to use the [`^`](`^/1`) operator:

```elixir
iex> x = 1
Expand Down Expand Up @@ -69,7 +69,7 @@ The documentation for the `Kernel` module lists all available guards in its side

## if

`case` builds on pattern matching and guards to destructure and match on certain conditions. However, patterns and guards are limited only to certain expressions which are optimized by the compiler. In many situations, you need to write conditions that go beyond what can be expressed with `case`. For those, `if/2` is a useful alternative:
[`case`](`case/2`) builds on pattern matching and guards to destructure and match on certain conditions. However, patterns and guards are limited only to certain expressions which are optimized by the compiler. In many situations, you need to write conditions that go beyond what can be expressed with [`case`](`case/2`). For those, [`if`](`if/2`) is a useful alternative:

```elixir
iex> if true do
Expand All @@ -82,9 +82,9 @@ iex> if false do
nil
```

If the condition given to `if/2` returns `false` or `nil`, the body given between `do`-`end` is not executed and instead it returns `nil`.
If the condition given to [`if`](`if/2`) returns `false` or `nil`, the body given between `do`-`end` is not executed and instead it returns `nil`.

`if/2` also supports `else` blocks:
[`if`](`if/2`) also supports `else` blocks:

```elixir
iex> if nil do
Expand All @@ -95,7 +95,7 @@ iex> if nil do
"This will"
```

This is also a good opportunity to talk about variable scoping in Elixir. If any variable is declared or changed inside `if`, `case`, and similar constructs, the declaration and change will only be visible inside the construct. For example:
This is also a good opportunity to talk about variable scoping in Elixir. If any variable is declared or changed inside [`if`](`if/2`), [`case`](`case/2`), and similar constructs, the declaration and change will only be visible inside the construct. For example:

```elixir
iex> x = 1
Expand All @@ -108,7 +108,7 @@ iex> x
1
```

In said cases, if you want to change a value, you must return the value from the `if`:
In said cases, if you want to change a value, you must return the value from the [`if`](`if/2`):

```elixir
iex> x = 1
Expand All @@ -123,13 +123,13 @@ iex> x = if true do

> #### `if` is a macro {: .info}
>
> An interesting note regarding `if/2` is that it is implemented as a macro in the language: it isn't a special language construct as it would be in many languages. You can check the documentation and its source for more information.
> An interesting note regarding [`if`](`if/2`) is that it is implemented as a macro in the language: it isn't a special language construct as it would be in many languages. You can check the documentation and its source for more information.

If you find yourself nesting several `if/2` blocks, you may want to consider using `cond/1` instead. Let's check it out.
If you find yourself nesting several [`if`](`if/2`) blocks, you may want to consider using [`cond`](`cond/1`) instead. Let's check it out.

## cond

If you need to check across several conditions and find the first one that does not evaluate to `nil` or `false`, `cond/1` is a useful construct:
If you need to check across several conditions and find the first one that does not evaluate to `nil` or `false`, [`cond`](`cond/1`) is a useful construct:

```elixir
iex> cond do
Expand Down Expand Up @@ -159,7 +159,7 @@ iex> cond do
"This is always true (equivalent to else)"
```

Similar to `if/2`, `cond` considers any value besides `nil` and `false` to be true:
Similar to [`if`](`if/2`), [`cond`](`cond/1`) considers any value besides `nil` and `false` to be true:

```elixir
iex> cond do
Expand All @@ -171,4 +171,4 @@ iex> cond do

## Summing up

We have concluded the introduction to the most fundamental control-flow constructs in Elixir. Generally speaking, Elixir developers prefer pattern matching and guards, using `case` and function definitions (which we will explore in future chapters), as they are succinct and precise. When your logic cannot be outlined within patterns and guards, you may consider `if/2`, falling back to `cond/1` when there are several conditions to check.
We have concluded the introduction to the most fundamental control-flow constructs in Elixir. Generally speaking, Elixir developers prefer pattern matching and guards, using [`case`](`case/2`) and function definitions (which we will explore in future chapters), as they are succinct and precise. When your logic cannot be outlined within patterns and guards, you may consider [`if`](`if/2`), falling back to [`cond`](`cond/1`) when there are several conditions to check.
22 changes: 11 additions & 11 deletions lib/elixir/pages/getting-started/lists-and-tuples.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ iex> length([1, 2, 3])
3
```

Two lists can be concatenated or subtracted using the `++/2` and `--/2` operators respectively:
Two lists can be concatenated or subtracted using the [`++`](`++/2`) and [`--`](`--/2`) operators respectively:

```elixir
iex> [1, 2, 3] ++ [4, 5, 6]
Expand All @@ -24,7 +24,7 @@ iex> [1, true, 2, false, 3, true] -- [true, false]

List operators never modify the existing list. Concatenating to or removing elements from a list returns a new list. We say that Elixir data structures are *immutable*. One advantage of immutability is that it leads to clearer code. You can freely pass the data around with the guarantee no one will mutate it in memory - only transform it.

Throughout the tutorial, we will talk a lot about the head and tail of a list. The head is the first element of a list and the tail is the remainder of the list. They can be retrieved with the functions `hd/1` and `tl/1`. Let's assign a list to a variable and retrieve its head and tail:
Throughout the tutorial, we will talk a lot about the head and tail of a list. The head is the first element of a list and the tail is the remainder of the list. They can be retrieved with the functions [`hd`](`hd/1`) and [`tl`](`tl/1`). Let's assign a list to a variable and retrieve its head and tail:

```elixir
iex> list = [1, 2, 3]
Expand All @@ -50,7 +50,7 @@ iex> [104, 101, 108, 108, 111]
~c"hello"
```

When Elixir sees a list of printable ASCII numbers, Elixir will print that as a charlist (literally a list of characters). Charlists are quite common when interfacing with existing Erlang code. Whenever you see a value in IEx and you are not quite sure what it is, you can use the `i/1` to retrieve information about it:
When Elixir sees a list of printable ASCII numbers, Elixir will print that as a charlist (literally a list of characters). Charlists are quite common when interfacing with existing Erlang code. Whenever you see a value in IEx and you are not quite sure what it is, you can use [`i`](`IEx.Helpers.i/1`) to retrieve information about it:

```elixir
iex> i ~c"hello"
Expand Down Expand Up @@ -96,7 +96,7 @@ iex> tuple_size(tuple)
2
```

It is also possible to put an element at a particular index in a tuple with `put_elem/3`:
It is also possible to put an element at a particular index in a tuple with [`put_elem`](`put_elem/3`):

```elixir
iex> tuple = {:ok, "hello"}
Expand All @@ -107,7 +107,7 @@ iex> tuple
{:ok, "hello"}
```

Notice that `put_elem/3` returned a new tuple. The original tuple stored in the `tuple` variable was not modified. Like lists, tuples are also immutable. Every operation on a tuple returns a new tuple, it never changes the given one.
Notice that [`put_elem`](`put_elem/3`) returned a new tuple. The original tuple stored in the `tuple` variable was not modified. Like lists, tuples are also immutable. Every operation on a tuple returns a new tuple, it never changes the given one.

## Lists or tuples?

Expand Down Expand Up @@ -150,9 +150,9 @@ iex> String.split("hello beautiful world")
["hello", "beautiful", "world"]
```

The `String.split/1` function breaks a string into a list of strings on every whitespace character. Since the amount of elements returned depends on the input, we use a list.
The [`String.split`](`String.split/1`) function breaks a string into a list of strings on every whitespace character. Since the amount of elements returned depends on the input, we use a list.

On the other hand, `String.split_at/2` splits a string in two parts at a given position. Since it always returns two entries, regardless of the input size, it returns tuples:
On the other hand, [`String.split_at`](`String.split_at/2`) splits a string in two parts at a given position. Since it always returns two entries, regardless of the input size, it returns tuples:

```elixir
iex> String.split_at("hello world", 3)
Expand All @@ -161,7 +161,7 @@ iex> String.split_at("hello world", -4)
{"hello w", "orld"}
```

It is also very common to use tuples and atoms to create "tagged tuples", which is a handy return value when an operation may succeed or fail. For example, `File.read/1` reads the contents of a file at a given path, which may or may not exist. It returns tagged tuples:
It is also very common to use tuples and atoms to create "tagged tuples", which is a handy return value when an operation may succeed or fail. For example, [`File.read`](`File.read/1`) reads the contents of a file at a given path, which may or may not exist. It returns tagged tuples:

```elixir
iex> File.read("path/to/existing/file")
Expand All @@ -170,9 +170,9 @@ iex> File.read("path/to/unknown/file")
{:error, :enoent}
```

If the path given to `File.read/1` exists, it returns a tuple with the atom `:ok` as the first element and the file contents as the second. Otherwise, it returns a tuple with `:error` and the error description. As we will soon learn, Elixir allows us to *pattern match* on tagged tuples and effortlessly handle both success and failure cases.
If the path given to [`File.read`](`File.read/1`) exists, it returns a tuple with the atom `:ok` as the first element and the file contents as the second. Otherwise, it returns a tuple with `:error` and the error description. As we will soon learn, Elixir allows us to *pattern match* on tagged tuples and effortlessly handle both success and failure cases.

Given Elixir consistently follows those rules, the choice between lists and tuples get clearer as you learn and use the language. Elixir often guides you to do the right thing. For example, there is an `elem/2` function to access a tuple item:
Given Elixir consistently follows those rules, the choice between lists and tuples get clearer as you learn and use the language. Elixir often guides you to do the right thing. For example, there is an [`elem`](`elem/2`) function to access a tuple item:

```elixir
iex> tuple = {:ok, "hello"}
Expand All @@ -187,6 +187,6 @@ However, given you often don't know the number of elements in a list, there is n

When counting the elements in a data structure, Elixir also abides by a simple rule: the function is named `size` if the operation is in constant time (the value is pre-calculated) or `length` if the operation is linear (calculating the length gets slower as the input grows). As a mnemonic, both "length" and "linear" start with "l".

For example, we have used 4 counting functions so far: `byte_size/1` (for the number of bytes in a string), `tuple_size/1` (for tuple size), `length/1` (for list length) and `String.length/1` (for the number of graphemes in a string). We use `byte_size` to get the number of bytes in a string, which is a cheap operation. Retrieving the number of Unicode graphemes, on the other hand, uses `String.length/1`, and may be expensive as it relies on a traversal of the entire string.
For example, we have used 4 counting functions so far: [`byte_size`](`byte_size/1`) (for the number of bytes in a string), [`tuple_size`](`tuple_size/1`) (for tuple size), [`length`](`length/1`) (for list length) and [`String.length`](`String.length/1`) (for the number of graphemes in a string). We use [`byte_size`](`byte_size/1`) to get the number of bytes in a string, which is a cheap operation. Retrieving the number of Unicode graphemes, on the other hand, uses [`String.length`](`String.length/1`), and may be expensive as it relies on a traversal of the entire string.

Now that we are familiar with the basic data-types in the language, let's learn important constructs for writing code, before we discuss more complex data structures.
12 changes: 6 additions & 6 deletions lib/elixir/pages/getting-started/pattern-matching.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
# Pattern matching

In this chapter, we will learn why the `=` operator in Elixir is called the match operator and how to use it to pattern match inside data structures. We will learn about the pin operator `^` used to access previously bound values.
In this chapter, we will learn why the [`=`](`=/2`) operator in Elixir is called the match operator and how to use it to pattern match inside data structures. We will learn about the pin operator [`^`](`^/1`) used to access previously bound values.

## The match operator

We have used the `=` operator a couple times to assign variables in Elixir:
We have used the [`=`](`=/2`) operator a couple times to assign variables in Elixir:

```elixir
iex> x = 1
Expand All @@ -13,7 +13,7 @@ iex> x
1
```

In Elixir, the `=` operator is actually called *the match operator*. Let's see why:
In Elixir, the [`=`](`=/2`) operator is actually called *the match operator*. Let's see why:

```elixir
iex> x = 1
Expand All @@ -26,7 +26,7 @@ iex> 2 = x

Notice that `1 = x` is a valid expression, and it matched because both the left and right side are equal to 1. When the sides do not match, a `MatchError` is raised.

A variable can only be assigned on the left side of `=`:
A variable can only be assigned on the left side of [`=`](`=/2`):

```elixir
iex> 1 = unknown
Expand Down Expand Up @@ -92,7 +92,7 @@ iex> tail
[2, 3]
```

Similar to the `hd/1` and `tl/1` functions, we can't match an empty list with a head and tail pattern:
Similar to the [`hd`](`hd/1`) and [`tl`](`tl/1`) functions, we can't match an empty list with a head and tail pattern:

```elixir
iex> [head | tail] = []
Expand Down Expand Up @@ -123,7 +123,7 @@ iex> x = 2

However, there are times when we don't want variables to be rebound.

Use the pin operator `^` when you want to pattern match against a variable's *existing value* rather than rebinding the variable.
Use the pin operator [`^`](`^/1`) when you want to pattern match against a variable's *existing value* rather than rebinding the variable.

```elixir
iex> x = 1
Expand Down