Useful Elixir Links

The language: https://elixir-lang.org/

The forum https://elixirforum.com/

The school https://elixirschool.com/en/

Style Guide: https://github.com/christopheradams/elixir_style_guide

https://hexdocs.pm/elixir/master/naming-conventions.html

The package mangement: https://hex.pm/

Documentation: https://hexdocs.pm/

Salvaged from Stackoverflow:  https://riptutorial.com/elixir

The mentored exercism: https://exercism.io/my/tracks/elixir

This enables history memory across iex sessions (add to .zshrc):

export ELIXIR_ERL_OPTIONS="-kernel shell_history enabled"

List comprehensions: https://hashrocket.com/blog/posts/elixir-for-loops-go-beyond-comprehension

Profiling Elixir:  http://learningelixir.joekain.com/profiling-elixir/

Getting postgres up quickly for phoenix:

`

docker run -d -e POSTGRES_PASSWORD=postgres -p 5432:5432 postgres:11

Getting livebook up quickly:

docker run -p 8080:8080 livebook/livebook`

Setup for tests

  use ExUnit.Case
  doctest DemoTest

  describe "This is a group of tests" do

    setup [:fixtures]

    for i <- [1,2,3] do
      test "Number #{i} is positive" do
        refute unquote(i) < 1
      end
    end

    test "greets the world", %{expected_world: expected} do
      assert DemoTest.hello() == expected
    end
  end

  def fixtures(context) do
    context = context
      |> Map.put(:expected_world, :world)

    {:ok, context}
  end
RNA Transcription

Elixir has a very clean syntax for codepoints that would help here:

```?G``` is the codepoint of ```G```

Single quoted strings are simply lists of codepoints.
Double quoted strings are the binary type from Erlang.
If you use the codepoint syntax on both sides of your translation function then you can reduce this problem to an Enum.map call.

Unless you can handle an error "let it crash".

```Don’t code defensively - Joe Armstrong```
(http://erlang.org/download/armstrong_thesis_2003.pdf)

Elixir applications are usually constructed with supervisors (this is beyond the scope of these exercises):

https://elixir-lang.org/getting-started/mix-otp/supervisor-and-application.html


It's good practice in Elixir to make all helper functions private (defp). This helps the compiler to warn that they are not used (which is useful in itself) but also allows easy detection of typos.

.

Word Count

String.split has a ```trim: true option``` that will allow you to remove the replaces and do all the work in the split.

String.split can take a string, a list, or a regex in the second parameter.

This may help simplify the count function:

https://hexdocs.pm/elixir/Map.html#update/4

Here is a more general regex that may be of use:
~r/[^[:alnum:]\-]/u

For scan:
~r/[[:alnum:]\-]+/iu

https://hexdocs.pm/elixir/Regex.html#module-character-classes

Also, consider extracting the regex as a descriptively named module attribute.

https://elixir-lang.org/getting-started/binaries-strings-and-char-lists.html

.

Roman

Good solution

There are three solutions to this problem:
* Recursive
* Decimal
* Expand and reduce

Have a look at other students solutions.

Good luck with the next exercise.

.
Bob:

Using hardcoded test data is kind of cheating.

This is a simple problem and can be solved without using regex. There is nothing wrong with regex (Elixir's regex support is very powerful) it's just not needed here.

Can you solve this in 5 cond clauses with no nesting?
Extracting defp helper functions will avoid duplication and allow you to clearly state intent.

These may be of use:
https://hexdocs.pm/elixir/String.html#trim/1
https://hexdocs.pm/elixir/String.html#ends_with?/2
https://hexdocs.pm/elixir/String.html#downcase/2
https://hexdocs.pm/elixir/String.html#upcase/2

Hint:

String.upcase(input) != String.downcase(input) if there is a letter present.

Here is a style guide that may be of interest: https://github.com/christopheradams/elixir_style_guide

Elixir uses xxx? for query functions (as you have used), but the ```is_``` prefix is usually reserved for guard clauses (something that you will need for later exercises).

.

Bank Account

Good solution.
There are four solutions to this problem:
* GenServer
* Agents
* send/receive
* ets

There is one choice: do you close the process with the account?

You have chosen the simplest of the four.
Have a look at the other student's solutions.

Good luck with the next exercise.

.

Beer song:

Elixir supports multiple function clauses distinguished by pattern matching, this is clearer than using a guard clause (the first to match is used, so order is important):

```
def verse(2), do: ...
def verse(1), do: ...
def verse(0), do: ...
def verse(number), do: ...
```
This can be used here to make the code more readable at the expense of a little duplication. This will also allow you to eliminate all of the helper functions.

Elixir has multi-line strings delimited by ```"""```

You can combine the two lyrics functions with a default (param \\ default_value).

Enum.map_join is cleaner than the component parts.

Ranges are enumerable.

.


Robot Simulator

Consider using defguard to make the validation more explicit. Note that guards are limited in what they can use, you may need to use pattern matching in the parameters.

defguard is_position(x,y) when is_integer(x) and is_integer(y)

direction/1 and position/1 are clearer using pattern matching:

def direction(%{direction: dir}), do: dir

Consider using the map update syntax:

%{robot | position: new_position }

.
Bowling

You are using a lot of magic numbers, 10 in particular has multiple meanings. Consider extracting some module attributes.

Forth

Good solution.

Congratulations on completing the mentored track.

Have you considered becoming a Mentor? It's a great way to deepen your knowledge of the language.

Good luck with the next exercise.
.
Elixir Exercises Yet To Mentor:

 "Allergies"
 "Alphametics"
 "Atbash Cypher"
 "Palindrome Products"
 "Spiral Matrix"