DEV Community

bbronek
bbronek

Posted on Edited on

Beginning my journey with elixir Part II. Modules, Enum, Loops, Strings, Recursion, Tests.

So it's time for the second part of my journey with elixir.
I will try to explain in a clear way things I have lastly learned and also show you how to use the newly acquired knowledge to write some simple programs.
That being said, I encourage you to read and learn something really interesting 😃

Alt Text

1.Modules

Modules are used to organize functions in their own namespace, it is useful to allocate functions to modules in relation to their functionality.
Example :

defmodule Greetings do
 @moduledoc """
  Provides a function `greet/1` to greet a human
  """
  @doc """
  Prints a hello message

  ## Parameters

    - name: String 

  ## Examples

      iex> Greeter.greet("user324")
      "Good morning! user324"

      iex> Greeter.greet("Peter")
      "Good morning! Peter"

  """
  @greeting "Good morning!"

  def greet(name) do
    ~s(#{@greeting} #{name}.)
  end
end

defmodule Greetings2 do
  alias Greetings, as: Hi

  def main do
    Hi.greet("John")
  end
end

Enter fullscreen mode Exit fullscreen mode

As you can see I used the @greeting attribute to use it as a greeting in the greet function. The ~s is a sigil. What is it? Here is an answer: Sigils are special syntax to working with literals, you can read more about this here. I also used the alias to use functions from another module in a different one.

2.Enum

The Enum is a module to work with enumerables.
I will only show a few functions from this module because it contains over 70 functions. It will be all?, any?, chunk_every, chunk_by, each, map, min, filter, reduce, sort and uniq

-all?

iex>Enum.all?(["one","two","three"], fn(x) -> String.length(x) == 4 end)
false
Enum.all?(["one","two","thre"], fn(x) -> String.length(x) == 3 end)
true

Enter fullscreen mode Exit fullscreen mode

-any?

iex>Enum.any?(["one","two","three"], fn(x) -> String.length(x) == 4 end)
true
Enum.any?(["one","two","thre"], fn(x) -> String.length(x) == 5 end)
false

Enter fullscreen mode Exit fullscreen mode

-chunk_every

iex>Enum.chunk_every(["one","two","three"], 2) 
[["one", "two"], ["three"]]

Enter fullscreen mode Exit fullscreen mode

-chunk_by

iex>Enum.chunk_by(["world","universe","hi"], fn(x) -> String.length(x) end) 
[["world"], ["universe"], ["hi"]]

Enter fullscreen mode Exit fullscreen mode

-each

iex>Enum.each(["How","are","you","?"], fn(x) -> IO.puts(x) end) 
How
are
you
?
:ok


Enter fullscreen mode Exit fullscreen mode

-map

iex> Enum.map([0, 1, 2, 3], fn(x) -> x * x end)
[0, 1, 4, 9]

Enter fullscreen mode Exit fullscreen mode

-min

iex> Enum.min([1, 32, 42, -10])
-10
Enter fullscreen mode Exit fullscreen mode

-filter

iex> Enum.filter([1, 2, 3, 4], fn(x) -> rem(x, 2) == 0 end)
[2, 4]

Enter fullscreen mode Exit fullscreen mode

-reduce

iex> Enum.reduce(["a","b","c"], fn(x,acc)-> x <> acc end)
"cba"

Enter fullscreen mode Exit fullscreen mode

Explanation: acc is the first element of the list.
This how it works:

1. x = 'b' acc = 'a' -> out: "ba"
2. x = 'c' acc = "ba" -> out: "cba"
"cba"

Enter fullscreen mode Exit fullscreen mode

-sort

iex> Enum.sort([%{:val => 4}, %{:val => 1}], fn(x, y) -> x[:val] > y[:val] end)
[%{val: 4}, %{val: 1}]

Enter fullscreen mode Exit fullscreen mode

-uniq

iex>  Enum.uniq([1, 2, 3, 2, 1, 1, 1, 1, 1])
[1, 2, 3]

Enter fullscreen mode Exit fullscreen mode

3.Loops

-for loop


iex>for {_key, val} <- [one: 1, two: 2, three: 3], do: IO.puts _key

one
two
three

Enter fullscreen mode Exit fullscreen mode

iex> import Integer
Integer
iex> for x <- 1..20, is_even(x), do: IO.puts x
2
4
6
8
10
12
14
16
18
20

Enter fullscreen mode Exit fullscreen mode

-functional approach source


defmodule Loop do
   def print_multiple_times(msg, n) when n <= 1 do
      IO.puts msg
   end

   def print_multiple_times(msg, n) do
      IO.puts msg
      print_multiple_times(msg, n - 1)
   end
end

Enter fullscreen mode Exit fullscreen mode

Results :

iex> c("file.ex")
[Loop]
iex> Loop.print_multiple_times("HI",3)
HI
HI
HI
:ok
Enter fullscreen mode Exit fullscreen mode

4.Strings

-You can use ASCII to assign a string value.

iex> string = <<104,101,108,108,111>>
"Hello"

Enter fullscreen mode Exit fullscreen mode

-Easy for returning an ASCII value of a char :

iex>?a
97

Enter fullscreen mode Exit fullscreen mode

Anagram program :

defmodule Anagram do
  def anagrams?(a, b) when is_binary(a) and is_binary(b) do
    sort_string(a) == sort_string(b)
  end

  def sort_string(string) do
    string
    |> String.downcase()
    |> String.graphemes()
    |> Enum.sort()
  end
end

Enter fullscreen mode Exit fullscreen mode

Useful link grapheme.

5.Short view of recursion.

defmodule Rec do
  def rec(a,b) do
    if a<=b do
      IO.puts "Hi #{a}"
      a = a + 1
      rec(a,b)
    end
  end
end

Enter fullscreen mode Exit fullscreen mode

Results:

[Rec]
iex> Rec.rec(2,7)
Hi 2
Hi 3
Hi 4
Hi 5
Hi 6
Hi 7
nil

Enter fullscreen mode Exit fullscreen mode

6. Tests

I wrote a simple program and I hope that it will be useful in understanding the methods of testing.

defmodule App do

    def get_name do
      IO.gets("What is yout name? ")
      |>String.trim
    end

    def get_number do
      IO.getn("Give a number: [0-9] ",1)
    end

    def main() do
      name = get_name()
      IO.puts("Hello #{name}")
      number = get_number()
      name
    end

end

ExUnit.start

defmodule Tests do
  alias App
  use ExUnit.Case

  test "check if name is valid" do
    refute String.match?(App.main,~r/[0-9]/)
  end
end

Enter fullscreen mode Exit fullscreen mode

Explanation: IO.getn(string,size) , ~r/[0-9]/ (regex);

Before testing, you have to launch it by ExUnit.start,
to use the test condition I had to write before it use ExUnit.Case. ' refute String.match?(App.main,~r/[0-9]/) '
refute it is the same as unless, you can also use assert in testing which means 'should' or 'expect to be' .

Result:

What is your name? qwer45
Hello qwer45
Give a number: [0-9] 5

1) test check if name is valid (Tests)
     tests.exs:27
     Expected false or nil, got true
     code: refute String.match?(App.main, ~r"[0-9]")
     arguments:

         # 1
         "qwer45"

         # 2
         ~r/[0-9]/

     stacktrace:
       tests.exs:28: (test)



Finished in 4.8 seconds (0.07s on load, 4.7s on tests)
1 test, 1 failure


Enter fullscreen mode Exit fullscreen mode

This all for part II in the next part I plan to write about using dates and times, custom mix tasks, more about iex, error handling, and executable files. Have a nice day ✋

Top comments (0)