
Elixir, a cool programming language:
Do you need to learn Erlang first?Nah, you got this. But if you already know Erlang, you might find this Elixir crash course for Erlang developers useful to get started. In either case, it’s important to know that Elixir programs can always, and sometimes have to, invoke functions from Erlang libraries. Elixir did not set out to rewrite the entire Erlang ecosystem; rather, it set out to modernize Erlang the language.
Jeff’s intro:
The Hello World program in Elixir is:
IO.puts "Hello, world"
You can run Elixir scripts on your favorite online runner (OneCompiler, TIO, etc.) or install Elixir on your own machine. Installing on your own machine will create several executables: (1) iex, an interactive shell, (2) elixir, to run scripts, (3) elixirc, to compile files, and (4) mix, the build tool.
After installing, run your script:
$ elixir hello.exs Hello, world
Filename extensions
Use the extension.exsfor scripts (files you intend to run as programs), and.exfor modules (containing objects and services you export to other modules and scripts).
Now, check out this little script:
Enum.each 1..40, fn c ->
Enum.each 1..c, fn b ->
Enum.each 1..b, fn a ->
if a * a + b * b == c * c do
IO.puts "#{a}, #{b}, #{c}"
end
end
end
end
$ elixir triple.exs 3, 4, 5 6, 8, 10 5, 12, 13 9, 12, 15 8, 15, 17 12, 16, 20 15, 20, 25 7, 24, 25 10, 24, 26 20, 21, 29 18, 24, 30 16, 30, 34 21, 28, 35 12, 35, 37 15, 36, 39 24, 32, 40
Here’s another script, this time with a command line argument:
defmodule Collatz do
def steps(n, count \\ 0) do
cond do
n == 1 -> count
rem(n, 2) == 0 -> steps div(n, 2), count + 1
true -> steps 3 * n + 1, count + 1
end
end
end
if length(System.argv) != 1 do
IO.puts "Exactly one command line argument required"
else
case System.argv |> hd |> Integer.parse do
:error -> IO.puts "Integer command line required"
{n, _} -> IO.puts Collatz.steps(n)
end
end
Neat, huh?
cond for multiway conditionals, if for simple conditionals, and case for pattern matching.|> operator is quite cool, right?Okay, time to go deeper.
Let’s illustrate a few things with IEx:
$ iex
Erlang/OTP 23 [erts-11.1.3] [source] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:1] [hipe] [dtrace]
Interactive Elixir (1.11.2) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)> 9 * (3 - 2) < 89
true
iex(2)> 3 <= 5 and 8 > 13 or not true
false
iex(3)> "dog" <> "house"
"doghouse"
iex(4)> [h | t] = [1, 2, 3, 4]
[1, 2, 3, 4]
iex(5)> h
1
iex(6)> t
[2, 3, 4]
iex(7)> [x, y, z] = [10, 20, 30]
[10, 20, 30]
iex(8)> y * z
600
iex(9)> first..last = 2..89
2..89
iex(10)> last
89
iex(11)> colors = %{red: "rojo", green: "verde", blue: "azul"}
%{blue: "azul", green: "verde", red: "rojo"}
iex(12)> colors[:green]
"verde"
iex(13)> colors.green
"verde"
These are the basic types (as far as I know, anyway, there may be more):
| Type | Description | Examples |
|---|---|---|
| Integer | Whole number. Unbounded, yay. |
398532129775303191288881231230x3ffa0b01101001
|
| Float | Floating-point number. |
3.1527.88E-200
|
| Atom | A (named) symbol. Starts with a colon. |
:ok:blue:empty:true
|
| List | A sequence of values stored as a linked list in memory. |
[1, :ok, "hello"][][[1, 2], [3, 4]]
|
| Tuple | A sequence of values stored contiguously in memory. |
{1, :ok, "hello"}{}{:rectangle 30.0 22.95}
|
| BitString | A sequence of bits stored contiguously in memory. |
<<7::3, 89::24, 1::8>><<97, 98, 99>>"Hello 🙌🧇🦊🥑"
|
| Map | Key-value pairs. Note the shorthand syntax when the keys are atoms. |
%{:a => 1, 2 => :b}%{"z" => true, 1 => 0, 0 => 1}%{:red => "rojo", :blue => "azul"}%{red: "rojo", blue: "azul"}
|
| Function | A function. |
fn x -> not x endfn -> 0 endfn x, y -> 2 * x + y endfn f, x -> f.(f.(x)) end&"Good #{&1}, #{&2}"&(&1 * 2 + &2)&String.reverse/1
|
| PID | Identifier for an Elixir process. The pid of the currently executing process is obtained by calling self/0. |
selfspawn(fn -> 0 end)
|
| Port | A thing you use to communicate with external processes. |
Port.open({:spawn, "ls"}, [])
|
| Reference | A unique identifier, generated on demand with make_ref/0. | make_ref |
In Elixir, types are not objects. In fact, you can’t cleanly “get” the type of an expression; instead, you have functions that return whether or not an expression has a type:
# Checks on the basic types
true = is_integer 8919821982888885323298
false = is_integer 5.0
true = is_float 2.0
true = is_atom :ok
true = is_atom :false
true = is_atom false
true = false == :false
true = is_atom nil
true = is_tuple {"Hi", 3, :true}
true = is_list ["Hi", 3, :true]
true = is_function(fn x -> x * x end)
true = is_map %{x: 3, y: 5}
true = is_bitstring <<7::3, 199, 8000::31>>
true = is_bitstring <<420>>
true = is_bitstring "Elixir is cool 😎💃🏽😍"
true = is_pid self()
true = is_reference make_ref()
# Other checks (numnber, boolean, nil, binary)
true = is_number(9.8)
true = is_number(5)
true = is_boolean(true)
true = is_boolean(false)
true = is_boolean(:false)
true = is_nil(nil)
false = is_binary <<7::3, 199, 8000::31>>
true = is_binary <<420>>
true = is_binary "Elixir is cool 😎💃🏽😍"
IO.puts("Everything checks out!")
Things that are not exactly typesThese all have built-in test functions (
booleanThe atoms :trueand:false. Elixir binds the namestrueandfalseto these, respectively, as a convenience.nilThe atom :nil. Elixir binds the namenilto this as a convenience.numberAll the integers and floats. binaryBitstrings in which the number of bits is divisible by 8. is_boolean,is_nil,is_number, andis_binary) functions, but the actual datatype for their values is something else.
Technically, there is a hack to get the type, though: if you are using IEx, you can use the inspect function i to get a ton of useful information about a value, including its type:
iex(1)> i "Happy 🎃 Day, いずみ" Term "Happy 🎃 Day, いずみ" Data type BitString Byte size 25 Description This is a string: a UTF-8 encoded binary. It's printed surrounded by "double quotes" because all UTF-8 encoded code points in it are printable. Raw representation <<72, 97, 112, 112, 121, 32, 240, 159, 142, 131, 32, 68, 97, 121, 44, 32, 227, 129, 132, 227, 129, 154, 227, 129, 191>> Reference modules String, :binary Implemented protocols Collectable, IEx.Info, Inspect, List.Chars, String.Chars
i function in IEx on a number of different values, with the intent about learning more about Elixir types. Try it on each of the examples in the table above.
Elixir’s integer type is unbounded, and the float type is probably IEEE binary-64, but the docs don’t seem to require this. In fact, Elixir does not seem to do Infinity and NaN like other languages!
is_float 8
TODO
Atoms are just atoms, or just symbols, they’re just what they are. So the atom :dog is just the atom :dog. It is not text. It is not a string. It is just :dog.
The atoms :true, :false, and :nil are so special you can write them false, and nil. The first two are called booleans but you already knew that. The atom nil is used to represent that something is missing or unknown.
TODO
Most languages need to manipulate text. Do we need a string type? Not really, the reasons for it aren’t that great. In fact, strings and text are not the same. And in most languages that have string types, their string type is badly broken. Few languages, if any, get text right. Swift and Elixir do text pretty well.
In Elixir, a string is just a binary that is a valid UTF-8 sequence.
TODO
You make your own types with structs and protocols:
TODO
There are more types in the Elixir Standard Library (some of which you’ll notice have a neat syntax):
TODO
Functions come in two flavors: (1) named functions, defined with def or defp inside a module, and (2) anonymous functions of the form fn params -> expression (or a short form). You can call the former with or without parenthesizing the arguments; the latter requires a dot plus parentheses for its arguments. If there are no arguments, you just invoke the function via its name (or the variable it has been assigned to). To refer to the function without calling it, use the & prefix.
TODO
TODO
TODO
TODO
TODO
TODO
TODO
TODO
TODO
Like what you see here? Want to learn more? Want to get really good at this cool language? Check out:
We’ve covered: