|
| 1 | +--- |
| 2 | +layout: getting-started |
| 3 | +title: Erlang libraries |
| 4 | +--- |
| 5 | + |
| 6 | +# {{ page.title }}<span hidden>.</span> |
| 7 | + |
| 8 | +{% include toc.html %} |
| 9 | + |
| 10 | +Elixir provides excellent interoperability with Erlang libraries. You will not |
| 11 | +find Elixir wrappers for libraries and applications from the Erlang standard |
| 12 | +library in the Elixir standard library. Instead, you are encouraged to use the |
| 13 | +Erlang libraries directly. In this section we will present some of the most |
| 14 | +common and useful Erlang libraries that are not found in Elixir core libraries. |
| 15 | + |
| 16 | +As you grow more proficient in Elixir, you may want to explore the Erlang |
| 17 | +[STDLIB Reference Manual](http://erlang.org/doc/apps/stdlib/index.html) in more |
| 18 | +detail. |
| 19 | + |
| 20 | + |
| 21 | + |
| 22 | + |
| 23 | +## The binary module |
| 24 | + |
| 25 | +The built-in Elixir String module handles binaries that are encoded in utf-8 |
| 26 | +format. The binary module is useful when you are dealing with binary data that |
| 27 | +is not necessarily utf-8 encoded. |
| 28 | + |
| 29 | +```iex |
| 30 | +iex> String.to_char_list "Ø" |
| 31 | +[216] |
| 32 | +iex> :binary.bin_to_list "Ø" |
| 33 | +[195, 152] |
| 34 | +``` |
| 35 | + |
| 36 | +The above example shows the difference; the `String` module returns utf-8 |
| 37 | +codepoints, while `:binary` deals with raw data bytes. |
| 38 | + |
| 39 | +## Formatted text output |
| 40 | + |
| 41 | +Elixir does not contain a function similar to C `printf`. An option is relying |
| 42 | +on string interpolation that is built into the language to do this, eg.: |
| 43 | + |
| 44 | +```iex |
| 45 | +iex> f = Float.to_string(:math.pi, decimals: 3) |> String.rjust(10) |
| 46 | +iex> str = "Pi is approximately given by: #{f}" |
| 47 | +"Pi is approximately given by: 3.142" |
| 48 | +``` |
| 49 | + |
| 50 | +Alternatively, the Erlang standard library functions `:io.format\2` and |
| 51 | +`:io_lib.format\2` may be used. The first formats to terminal output, while the |
| 52 | +second formats to a string. The format specifiers differ from `printf`, refer |
| 53 | +to the Erlang documentation for details. |
| 54 | + |
| 55 | +```iex |
| 56 | +iex> :io.format("Pi is approximately given by:~10.3f~n", [:math.pi]) |
| 57 | +Pi is approximately given by: 3.142 |
| 58 | +:ok |
| 59 | +iex> str = :io_lib.format("Pi is approximately given by:~10.3f~n", [:math.pi]) |> IO.iodata_to_binary |
| 60 | +"Pi is approximately given by: 3.142\n" |
| 61 | +``` |
| 62 | + |
| 63 | +Also note that Erlangs formatting functions require special attention to |
| 64 | +unicode handling. |
| 65 | + |
| 66 | +## The calendar module |
| 67 | + |
| 68 | +The calendar module contains functions for conversion between local and |
| 69 | +universal time, as well as time conversion functions. |
| 70 | + |
| 71 | +```iex |
| 72 | +iex> :calendar.day_of_the_week(1980, 6, 28) |
| 73 | +6 |
| 74 | +iex> :calendar.now_to_local_time(:erlang.timestamp) |
| 75 | +{{2016, 2, 17}, {22, 4, 55}} |
| 76 | +``` |
| 77 | + |
| 78 | +## The crypto module |
| 79 | + |
| 80 | +The crypto module contains hashing functions, digital signatures, encryption |
| 81 | +and more. The library also contains the `crypto` application that must be |
| 82 | +registered as a dependency to your application for some of this functionality |
| 83 | +to work. |
| 84 | + |
| 85 | +To do this, edit your `mix.exs` file to include: |
| 86 | + |
| 87 | +```elixir |
| 88 | + def application do |
| 89 | + [applications: [:crypto]] |
| 90 | + end |
| 91 | +``` |
| 92 | + |
| 93 | +The `crypto` module is not part of the Erlang standard library, but is included |
| 94 | +with the Erlang distribution. The documentation is found at |
| 95 | +[this page](http://erlang.org/doc/man/crypto.html). |
| 96 | + |
| 97 | +```iex |
| 98 | +iex> Base.encode16(:crypto.hash(:sha256, "Elixir")) |
| 99 | +"3315715A7A3AD57428298676C5AE465DADA38D951BDFAC9348A8A31E9C7401CB" |
| 100 | +``` |
| 101 | + |
| 102 | +## The digraph module |
| 103 | + |
| 104 | +The `digraph` and `digraph_utils` modules contain functions for dealing with |
| 105 | +directed graphs built of vertices and edges. After constructing the graph, the |
| 106 | +algorithms in here will help finding for instance the shortest path between two |
| 107 | +vertices, or loops in the graph. |
| 108 | + |
| 109 | +Note that the functions in :digraph alter the graph structure indirectly as a |
| 110 | +side effect, while returning the added vertices or edges. |
| 111 | + |
| 112 | +Given three vertices, find the shortest path from the first to the last. |
| 113 | + |
| 114 | +```iex |
| 115 | +iex> digraph = :digraph.new() |
| 116 | +iex> coords = [{0.0, 0.0}, {1.0, 0.0}, {1.0, 1.0}] |
| 117 | +iex> for c <- coords, do: :digraph.add_vertex(digraph, c) |
| 118 | +iex> [v0, v1, v2] = (for c <- coords, do: :digraph.add_vertex(digraph, c)) |
| 119 | +iex> :digraph.add_edge(digraph, v0, v1) |
| 120 | +iex> :digraph.add_edge(digraph, v1, v2) |
| 121 | +iex> :digraph.get_short_path(digraph, v0, v2) |
| 122 | +[{0.0, 0.0}, {1.0, 0.0}, {1.0, 1.0}] |
| 123 | +``` |
| 124 | + |
| 125 | + |
| 126 | +## Erlang Term Storage |
| 127 | + |
| 128 | +The modules `ets` and `dets` handle storage of large data structures in memory |
| 129 | +or on disk respectively. |
| 130 | + |
| 131 | +ETS lets you create a table containing tuples that is owned by a single |
| 132 | +process. For large amounts of data, ETS may be more performant than storing |
| 133 | +data as large Elixir data structures. ETS has some functionality to be used as |
| 134 | +a simple database or key-value store. |
| 135 | + |
| 136 | +The functions in the `ets` module will modify the state of the table as a side |
| 137 | +effect. |
| 138 | + |
| 139 | +```iex |
| 140 | +iex> table = :ets.new(:ets_test, []) |
| 141 | +iex> :ets.insert(table, {%{name: "China", population: 1_374_000_000}}) |
| 142 | +iex> :ets.insert(table, {%{name: "India", population: 1_284_000_000}}) |
| 143 | +iex> :ets.insert(table, {%{name: "USA", population: 322_000_000}}) |
| 144 | +iex> :ets.i(table) |
| 145 | +<1 > {#{name => <<"USA">>,population => 322000000}} |
| 146 | +<2 > {#{name => <<"China">>,population => 1374000000}} |
| 147 | +<3 > {#{name => <<"India">>,population => 1284000000}} |
| 148 | +``` |
| 149 | + |
| 150 | +ETS is described in more detail in it's own section. |
| 151 | + |
| 152 | +## The math module |
| 153 | + |
| 154 | +The `math` module contains common mathematical operations covering trigonometry, |
| 155 | +exponential and logarithmic functions. |
| 156 | + |
| 157 | +```iex |
| 158 | +iex> angle_45_deg = :math.pi() * 45.0 / 180.0 |
| 159 | +iex> :math.sin(angle_45_deg) |
| 160 | +0.7071067811865475 |
| 161 | +iex> :math.exp(55.0) |
| 162 | +7.694785265142018e23 |
| 163 | +iex> :math.log(7.694785265142018e23) |
| 164 | +55.0 |
| 165 | +``` |
| 166 | + |
| 167 | + |
| 168 | +## The queue module |
| 169 | + |
| 170 | +The `queue` is a data structure that allows efficient FIFO (first in first out) |
| 171 | +operation. |
| 172 | + |
| 173 | +A regular Elixir list may not be performant as removing the first element in |
| 174 | +the list requires building a new list with the remaining elements, not reusing |
| 175 | +any data. |
| 176 | + |
| 177 | +```iex |
| 178 | +iex> q = :queue.new |
| 179 | +iex> q = :queue.in("A", q) |
| 180 | +iex> q = :queue.in("B", q) |
| 181 | +iex> q = :queue.in("C", q) |
| 182 | +iex> {_, q} = :queue.out(q) |
| 183 | +{{:value, "A"}, {["C"], ["B"]}} |
| 184 | +iex> {_, q} = :queue.out(q) |
| 185 | +{{:value, "B"}, {[], ["C"]}} |
| 186 | +iex> {_, q} = :queue.out(q) |
| 187 | +{{:value, "C"}, {[], []}} |
| 188 | +iex> {_, q} = :queue.out(q) |
| 189 | +{:empty, {[], []}} |
| 190 | +``` |
| 191 | + |
| 192 | +## The rand module |
| 193 | + |
| 194 | +This module has functions for returning random values and setting the random |
| 195 | +seed. |
| 196 | + |
| 197 | +```iex |
| 198 | +iex> :rand.uniform() |
| 199 | +0.8175669086010815 |
| 200 | +iex> _ = :rand.seed(:exs1024, {123, 123534, 345345}) |
| 201 | +iex> :rand.uniform() |
| 202 | +0.5820506340260994 |
| 203 | +iex> :rand.uniform(6) |
| 204 | +6 |
| 205 | +``` |
| 206 | + |
| 207 | +## The zlib and zip modules |
| 208 | + |
| 209 | +The `zip` module lets you read and write zip files to and from disk or memory, |
| 210 | +as well as extracting file information. |
| 211 | + |
| 212 | +This code counts the number of files in a zip file: |
| 213 | + |
| 214 | +```iex |
| 215 | +iex> :zip.foldl(fn _, _, _, acc -> acc + 1 end, 0, :binary.bin_to_list("file.zip")) |
| 216 | +{:ok, 633} |
| 217 | +``` |
| 218 | + |
| 219 | +The `zlib` module deals with data compression in zlib format, as found in the |
| 220 | +`gzip` command. |
| 221 | + |
| 222 | +```iex |
| 223 | +iex> song = " |
| 224 | +...> Mary had a little lamb, |
| 225 | +...> His fleece was white as snow, |
| 226 | +...> And everywhere that Mary went, |
| 227 | +...> The lamb was sure to go." |
| 228 | +iex> compressed = :zlib.compress(song) |
| 229 | +iex> byte_size song |
| 230 | +110 |
| 231 | +iex> byte_size compressed |
| 232 | +99 |
| 233 | +iex> :zlib.uncompress(compressed) |
| 234 | +"\nMary had a little lamb,\nHis fleece was white as snow,\nAnd everywhere that Mary went,\nThe lamb was sure to go." |
| 235 | +``` |
| 236 | + |
0 commit comments