Skip to content

Commit

Permalink
exercises/concept: run configlet generate that uses cmark
Browse files Browse the repository at this point in the history
  • Loading branch information
ee7 committed Jun 24, 2022
1 parent f95a81a commit d05c1e7
Show file tree
Hide file tree
Showing 41 changed files with 298 additions and 355 deletions.
6 changes: 3 additions & 3 deletions exercises/concept/basketball-website/.docs/introduction.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@

## Access Behaviour

Elixir uses code _Behaviours_ to provide common generic interfaces while facilitating specific implementations for each module which implements it. One such common example is the _Access Behaviour_.
Elixir uses code *Behaviours* to provide common generic interfaces while facilitating specific implementations for each module which implements it. One such common example is the *Access Behaviour*.

The _Access Behaviour_ provides a common interface for retrieving data from a key-based data structure. The _Access Behaviour_ is implemented for maps and keyword lists, but let's look at its use for maps to get a feel for it. _Access Behaviour_ specifies that when you have a map, you may follow it with _square brackets_ and then use the key to retrieve the value associated with that key.
The *Access Behaviour* provides a common interface for retrieving data from a key-based data structure. The *Access Behaviour* is implemented for maps and keyword lists, but let's look at its use for maps to get a feel for it. *Access Behaviour* specifies that when you have a map, you may follow it with *square brackets* and then use the key to retrieve the value associated with that key.

```elixir
``` elixir
# Suppose we have these two maps defined (note the difference in the key type)
my_map = %{key: "my value"}
your_map = %{"key" => "your value"}
Expand Down
6 changes: 3 additions & 3 deletions exercises/concept/bird-count/.docs/introduction.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,13 @@

Recursive functions are functions that call themselves.

A recursive function needs to have at least one _base case_ and at least one _recursive case_.
A recursive function needs to have at least one *base case* and at least one *recursive case*.

A _base case_ returns a value without calling the function again. A _recursive case_ calls the function again, modifying the input so that it will at some point match the base case.
A *base case* returns a value without calling the function again. A *recursive case* calls the function again, modifying the input so that it will at some point match the base case.

Very often, each case is written in its own function clause.

```elixir
``` elixir
# base case
def count([]), do: 0

Expand Down
10 changes: 3 additions & 7 deletions exercises/concept/boutique-inventory/.docs/introduction.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@

`Enum` is a very useful module that provides a set of algorithms for working with enumerables. It offers sorting, filtering, grouping, counting, searching, finding min/max values, and much more.

In general, an _enumerable_ is any data that can be iterated over, a collection. In Elixir, an enumerable is any data type that implements the `Enumerable` [protocol][exercism-protocols]. The most common of those are [lists][exercism-lists] and [maps][exercism-maps].
In general, an *enumerable* is any data that can be iterated over, a collection. In Elixir, an enumerable is any data type that implements the `Enumerable` [protocol](https://exercism.org/tracks/elixir/concepts/protocols). The most common of those are [lists](https://exercism.org/tracks/elixir/concepts/lists) and [maps](https://exercism.org/tracks/elixir/concepts/maps).

Many `Enum` functions accept a function as an argument.

```elixir
``` elixir
Enum.all?([1, 2, 3, 4, 5], fn x -> x > 3 end)
# => false
```
Expand All @@ -21,7 +21,7 @@ The most common `Enum` functions are `map` and `reduce`.

### `reduce/3`

`Enum.reduce/3` allows you to _reduce_ the whole enumerable to a single value. To achieve this, a special variable called the _accumulator_ is used. The accumulator carries the intermediate state of the reduction between iterations.
`Enum.reduce/3` allows you to *reduce* the whole enumerable to a single value. To achieve this, a special variable called the *accumulator* is used. The accumulator carries the intermediate state of the reduction between iterations.

The second argument to `Enum.reduce/3` is the initial value of the accumulator. The third argument is a function that accepts an element and an accumulator, and returns the new value for the accumulator.

Expand All @@ -36,7 +36,3 @@ To transform it back to a map, use `Enum.into/2`. `Enum.into/2` is a function th
#### Mapping maps

Instead of using `Enum.into/3` or `Enum.map/2` plus `Enum.into/1` to apply a transformation (mapping) to a map, we can also use a dedicated `Map.new/2` function. It works exactly like `Enum.into/3` in that it accepts an enumerable and a transformation function, but it always returns a new map instead of letting us choose a collectible.

[exercism-protocols]: https://exercism.org/tracks/elixir/concepts/protocols
[exercism-lists]: https://exercism.org/tracks/elixir/concepts/lists
[exercism-maps]: https://exercism.org/tracks/elixir/concepts/maps
16 changes: 8 additions & 8 deletions exercises/concept/boutique-suggestions/.docs/introduction.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,35 +2,35 @@

## List Comprehensions

Comprehensions provide a facility for transforming _Enumerables_ easily and declaratively.
Comprehensions provide a facility for transforming *Enumerables* easily and declaratively.

To declare a very simple comprehension, we can use the `for` keyword followed by a _generator_ and a _do-block_ which creates the new values from the enumerated values.
To declare a very simple comprehension, we can use the `for` keyword followed by a *generator* and a *do-block* which creates the new values from the enumerated values.

```elixir
``` elixir
for n <- [0, 1, 2, 3], do: n + 1
# => [1, 2, 3, 4]
```

Comprehensions can also have _filters_. Values that do not pass the filter are removed from the final list:
Comprehensions can also have *filters*. Values that do not pass the filter are removed from the final list:

```elixir
``` elixir
for n <- [0, 1, 2, 3], n > 1, do: n + 1
# => [3, 4]
```

We can declare more complicated comprehensions over several lines:

```elixir
``` elixir
for {atom, number} <- [a: 1, b: 2, c: 3, d: 4],
rem(number, 2) == 0 do
atom
end
# => [:b, :d]
```

A _cartesian product_ can be created using multiple generators. That means that each value generated by the first generator will be paired once with each value generated by the second generator:
A *cartesian product* can be created using multiple generators. That means that each value generated by the first generator will be paired once with each value generated by the second generator:

```elixir
``` elixir
for x <- [0, 1],
y <- [0, 1] do
{x, y}
Expand Down
4 changes: 2 additions & 2 deletions exercises/concept/bread-and-potions/.docs/introduction.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,15 @@ Protocols are a mechanism to achieve polymorphism in Elixir when you want behavi

Protocols are defined using `defprotocol` and contain one or more function headers.

```elixir
``` elixir
defprotocol Reversible do
def reverse(term)
end
```

Protocols can be implemented using `defimpl`.

```elixir
``` elixir
defimpl Reversible, for: List do
def reverse(term) do
Enum.reverse(term)
Expand Down
14 changes: 6 additions & 8 deletions exercises/concept/captains-log/.docs/introduction.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,18 +16,16 @@ Erlang's standard library is available for use in our Elixir code without any ex

Erlang functions can be called in the same way we call Elixir functions, with one small difference. Erlang module names are `snake_case` atoms. For example, to call the Erlang `pi/0` function from the `math` module, one would write:

```elixir
``` elixir
:math.pi()
# => 3.141592653589793
```

The most commonly used Erlang functions that do not have an Elixir equivalent are:

- `:timer.sleep/1` which suspends a process for the given amount of milliseconds.
- `:rand.uniform/0` which generates a random float `x`, where `0.0 <= x < 1.0`.
- `:io_lib.format/2` which provides C-style string formatting (using control sequences). Using this function, we could for example print an integer in any base between 2 and 36 or format a float with desired precision. Note that this function, like many Erlang functions, returns a charlist.
- The `math` module that provides mathematical functions such as `sin/1`, `cos/1`, `log2/1`, `log10/1`, `pow/2`, and more.
- `:timer.sleep/1` which suspends a process for the given amount of milliseconds.
- `:rand.uniform/0` which generates a random float `x`, where `0.0 <= x < 1.0`.
- `:io_lib.format/2` which provides C-style string formatting (using control sequences). Using this function, we could for example print an integer in any base between 2 and 36 or format a float with desired precision. Note that this function, like many Erlang functions, returns a charlist.
- The `math` module that provides mathematical functions such as `sin/1`, `cos/1`, `log2/1`, `log10/1`, `pow/2`, and more.

To discover Erlang's standard library, explore the [STDLIB Reference Manual][erl-stdlib-ref].

[erl-stdlib-ref]: http://www.erlang.org/doc/apps/stdlib/index.html
To discover Erlang's standard library, explore the [STDLIB Reference Manual](http://www.erlang.org/doc/apps/stdlib/index.html).
4 changes: 2 additions & 2 deletions exercises/concept/chessboard/.docs/introduction.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@

Ranges represent a sequence of one or many consecutive integers. They are created by connecting two integers with `..`.

```elixir
``` elixir
1..5
```

Ranges can be ascending or descending. They are always inclusive of the first and last values.

A range implements the _Enumerable protocol_, which means functions in the `Enum` module can be used to work with ranges.
A range implements the *Enumerable protocol*, which means functions in the `Enum` module can be used to work with ranges.
25 changes: 11 additions & 14 deletions exercises/concept/city-office/.docs/introduction.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ Documentation in Elixir is a first-class citizen.

There are two module attributes commonly used to document your code - `@moduledoc` for documenting a module and `@doc` for documenting a function that follows the attribute. The `@moduledoc` attribute usually appears on the first line of the module, and the `@doc` attribute usually appears right before a function definition, or the function's typespec if it has one. The documentation is commonly written in a multiline string using the heredoc syntax.

Elixir documentation is written in [**Markdown**][markdown].
Elixir documentation is written in [**Markdown**](https://docs.github.com/en/github/writing-on-github/basic-writing-and-formatting-syntax).

```elixir
``` elixir
defmodule String do
@moduledoc """
Strings in Elixir are UTF-8 encoded binaries.
Expand All @@ -35,7 +35,7 @@ Elixir is a dynamically typed language, which means it doesn't provide compile-t
A type specification can be added to a function using the `@spec` module attribute right before the function definition. `@spec` is followed by the function name and a list of all of its arguments' types, in parentheses, separated by commas. The type of the return value is separated from the function's arguments with a double colon `::`.
```elixir
``` elixir
@spec longer_than?(String.t(), non_neg_integer()) :: boolean()
def longer_than?(string, length), do: String.length(string) > length
```
Expand All @@ -44,39 +44,36 @@ def longer_than?(string, length), do: String.length(string) > length
Most commonly used types include:
- booleans: `boolean()`
- strings: `String.t()`
- numbers: `integer()`, `non_neg_integer()`, `pos_integer()`, `float()`
- lists: `list()`
- a value of any type: `any()`
- booleans: `boolean()`
- strings: `String.t()`
- numbers: `integer()`, `non_neg_integer()`, `pos_integer()`, `float()`
- lists: `list()`
- a value of any type: `any()`
Some types can also be parameterized, for example `list(integer)` is a list of integers.
Literal values can also be used as types.
A union of types can be written using the pipe `|`. For example, `integer() | :error` means either an integer or the atom literal `:error`.
A full list of all types can be found in the ["Typespecs" section in the official documentation][types].
A full list of all types can be found in the ["Typespecs" section in the official documentation](https://hexdocs.pm/elixir/typespecs.html#types-and-their-syntax).
### Naming arguments
Arguments in the typespec could also be named which is useful for distinguishing multiple arguments of the same type. The argument name, followed by a double colon, goes before the argument's type.

```elixir
``` elixir
@spec to_hex({hue :: integer, saturation :: integer, lightness :: integer}) :: String.t()
```

### Custom types

Typespecs aren't limited to just the built-in types. Custom types can be defined using the `@type` module attribute. A custom type definition starts with the type's name, followed by a double colon and then the type itself.

```elixir
``` elixir
@type color :: {hue :: integer, saturation :: integer, lightness :: integer}

@spec to_hex(color()) :: String.t()
```

A custom type can be used from the same module where it's defined, or from another module.
[markdown]: https://docs.github.com/en/github/writing-on-github/basic-writing-and-formatting-syntax
[types]: https://hexdocs.pm/elixir/typespecs.html#types-and-their-syntax
10 changes: 4 additions & 6 deletions exercises/concept/community-garden/.docs/introduction.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,15 @@

## Agent

The `Agent` module facilitates an abstraction for spawning [processes and the _receive-send_ loop][exercism-processes]. From here, we will call processes started using the `Agent` module _'agent processes'_. An _agent process_ might be chosen to represent a central shared state.
The `Agent` module facilitates an abstraction for spawning [processes and the *receive-send* loop](https://exercism.org/tracks/elixir/concepts/processes). From here, we will call processes started using the `Agent` module *'agent processes'*. An *agent process* might be chosen to represent a central shared state.

To start an _agent process_, `Agent` provides the `start/2` function. The supplied function when `start`_-ing_ the _agent process_ returns the initial state of the process:
To start an *agent process*, `Agent` provides the `start/2` function. The supplied function when `start`*-ing* the *agent process* returns the initial state of the process:

```elixir
``` elixir
# Start an agent process with an initial value of an empty list
{:ok, agent_pid} = Agent.start(fn -> [] end)
```

Just like `Map` or `List`, `Agent` provides many functions for working with _agent processes_.
Just like `Map` or `List`, `Agent` provides many functions for working with *agent processes*.

It is customary to organize and encapsulate all `Agent`-related functionality into a module for the domain being modeled.

[exercism-processes]: https://exercism.org/tracks/elixir/concepts/processes
26 changes: 11 additions & 15 deletions exercises/concept/dancing-dots/.docs/introduction.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ The `use` macro allows us to quickly extend our module with functionally provide

If you ever looked at the test files of some of the Elixir exercises here on Exercism, you most likely noticed that they all start with `use ExUnit.Case`. This single line of code is what makes the macros `test` and `assert` available in the test module.

```elixir
``` elixir
defmodule LasagnaTest do
use ExUnit.Case

Expand All @@ -18,9 +18,9 @@ end

### `__using__/1` macro

What exactly happens when you `use` a module is dictated by that module's `__using__/1` macro. It takes one argument, a keyword list with options, and it returns a [quoted expression][concept-ast]. The code in this quoted expression is inserted into our module when calling `use`.
What exactly happens when you `use` a module is dictated by that module's `__using__/1` macro. It takes one argument, a keyword list with options, and it returns a [quoted expression](https://exercism.org/tracks/elixir/concepts/ast). The code in this quoted expression is inserted into our module when calling `use`.

```elixir
``` elixir
defmodule ExUnit.Case do
defmacro __using__(opts) do
# some real-life ExUnit code omitted here
Expand All @@ -36,17 +36,17 @@ The options can be given as a second argument when calling `use`, e.g. `use ExUn

## Behaviours

Behaviours allow us to define interfaces (sets of functions and macros) in a _behaviour module_ that can be later implemented by different _callback modules_. Thanks to the shared interface, those callback modules can be used interchangeably.
Behaviours allow us to define interfaces (sets of functions and macros) in a *behaviour module* that can be later implemented by different *callback modules*. Thanks to the shared interface, those callback modules can be used interchangeably.

~~~~exercism/note
``` exercism/note
Note the British spelling of "behaviours".
~~~~
```

### Defining behaviours

To define a behaviour, we need to create a new module and specify a list of functions that are part of the desired interface. Each function needs to be defined using the `@callback` module attribute. The syntax is identical to a [function typespec][concept-typespecs] (`@spec`). We need to specify a function name, a list of argument types, and all the possible return types.
To define a behaviour, we need to create a new module and specify a list of functions that are part of the desired interface. Each function needs to be defined using the `@callback` module attribute. The syntax is identical to a [function typespec](https://exercism.org/tracks/elixir/concepts/typespecs) (`@spec`). We need to specify a function name, a list of argument types, and all the possible return types.

```elixir
``` elixir
defmodule Countable do
@callback count(collection :: any) :: pos_integer
end
Expand All @@ -56,13 +56,13 @@ end

To add an existing behaviour to our module (create a callback module) we use the `@behaviour` module attribute. Its value should be the name of the behaviour module that we're adding.

Then, we need to define all the functions (callbacks) that are required by that behaviour module. If we're implementing somebody else's behaviour, like Elixir's built-in `Access` or `GenServer` behaviours, we would find the list of all the behaviour's callbacks in the documentation on [hexdocs.pm][hexdocs].
Then, we need to define all the functions (callbacks) that are required by that behaviour module. If we're implementing somebody else's behaviour, like Elixir's built-in `Access` or `GenServer` behaviours, we would find the list of all the behaviour's callbacks in the documentation on [hexdocs.pm](https://hexdocs.pm).

A callback module is not limited to implementing only the functions that are part of its behaviour. It is also possible for a single module to implement multiple behaviours.

To mark which function comes from which behaviour, we should use the module attribute `@impl` before each function. Its value should be the name of the behaviour module that defines this callback.

```elixir
``` elixir
defmodule BookCollection do
@behaviour Countable

Expand All @@ -83,7 +83,7 @@ end

When defining a behaviour, it is possible to provide a default implementation of a callback. This implementation should be defined in the quoted expression of the `__using__/1` macro. To make it possible for users of the behaviour module to override the default implementation, call the `defoverridable/1` macro after the function implementation. It accepts a keyword list of function names as keys and function arities as values.

```elixir
``` elixir
defmodule Countable do
@callback count(collection :: any) :: pos_integer

Expand All @@ -98,7 +98,3 @@ end
```

Note that defining functions inside of `__using__/1` is discouraged for any other purpose than defining default callback implementations, but you can always define functions in another module and import them in the `__using__/1` macro.

[concept-ast]: https://exercism.org/tracks/elixir/concepts/ast
[concept-typespecs]: https://exercism.org/tracks/elixir/concepts/typespecs
[hexdocs]: https://hexdocs.pm
Loading

0 comments on commit d05c1e7

Please sign in to comment.