Skip to content

Instantly share code, notes, and snippets.

@mvoto
Last active November 16, 2018 19:20
Show Gist options
  • Save mvoto/8c11c70415cbbe27f10c9eda796d07ee to your computer and use it in GitHub Desktop.
Save mvoto/8c11c70415cbbe27f10c9eda796d07ee to your computer and use it in GitHub Desktop.
Programming Elixir Book

Quick Intro

  • Object Orientation is not the only way
  • Functional Programming need not be complex or mathematical
  • The bases of programming are not assignments, if statements and loops
  • Concurrency does not need locks, semaphores, monitors and the like
  • Processes are not necessarily expensive resources
  • Metaprogramming is not just something tacked onto a language
  • Even if it is work, programming should be fun

Pattern Matching

In Elixir equal sign is not an assignment. Its like an assertion. It succeeds if Elixir can find a way of making the left-hand side equal the right-hand side. Elixir calls "=" a match operator. For a = 1 "a" is a variable and "1" is an integer literal, so Elixir can make the match try by binding the variable a to value 1. To prove that this is not just an assignment:

iex> a = 1 1 iex> 1 = a 1 iex> 2 = a ** (MatchError) no match of right hand side value: 1

Since we first matched value 1 to variable a, when we perform 1 = a Elixir matches it, cause 1 matches 1. But when we try to match 2 = a Elixir does not allow it, cause 2 does not match 1, then raises an error.

More complex Matches:

iex(1)> list = [1,2,3] [1, 2, 3] iex(2)> [a,b,c] = list [1, 2, 3] iex(3)> a 1 iex(4)> b 2 iex(5)> c 3

Elixir looks for a way to make the value of the left side same as on the right side. If there is a list of 3 variables on the left side and a list of 3 values on the right side, then they match and values can be setup to the variables. This is called pattern matching - A pattern (left side) is matched if the values (right side) have the same structure and if each term in the pattern can be matched to the corresponding term in the values.

Ignoring a Value with _

If we dont want to capture a value during the match, wed can use a special variable _. This acts like a variable but immediatly discards any value given to it. So its possible to do things like:

iex(13)> [a,b,_]=[1,2,3]
[1, 2, 3]
iex(14)> [1, _, _] = [1,2,3]
[1, 2, 3]
iex(15)> [a,_,_] = ['cat', 1, 2]
['cat', 1, 2]

The Pin Operator

Is the way to force Elixir to use the existing value on that variable "locking" it to the previously assigned value by using a caret(^):

iex(18)> a=1
1
iex(19)> a=2
2
iex(20)> ^a=1
** (MatchError) no match of right hand side value: 1

Another qay of looking at the equals sign We can think about it same as used in algebra, so:

x = a + 1

You are not assigning the value a + 1 to x, you are simply asserting that expressions x and a + 1 have the same value.

Immutability

Imagine that(not on Elixir):

count = 99
do_something_with(count)
print(count)

You'd expect it to output 99. Value 99 would be always value 99. Now imagine programming in a world where you couldn't rely on that, where some other code, possibly running in parallel with your own, could change the value of 99. Imagine that suddently, 99 could be 100. Elixir sidesteps these problems, all values are immutable. The most complex nested list, the database record - this things behave just like the simplest integer. Their values are all immutable. Once a variable references a list such as [1,2,3], you know it will always reference those same values(until you rebind the variable). And this makes concurrency a lot less frightening. If you need to add 100 to each element in [1,2,3] Elixir does it by producing a copy of the original, containing the new values. The original remains unchanged, and your operation will not affect any other code holding a reference to that original. Programming is about transforming data.

Perofmance-wise It would be easy to assume that this approach to programming is inefficient. After all, you have to create a new copy of data whenever you update it, and that’s going to leave lots of old values around to be garbage-collected.

Consider this code. (It uses a new operator, [ head | tail ] , which builds a new list with head as its first element and tail as the rest. We’ll spend a whole chapter on this when we talk about lists and recursion. For now, just trust.) ​ ​ iex> ​ list1 = [ 3, 2, 1 ] ​ [3, 2, 1] ​ ​ iex> ​ list2 = [ 4 | list1 ] ​ [4, 3, 2, 1] In most languages, list2 would be built by creating a new list containing a 4, a 3, a 2, and a 1. The three values in list1 would be copied into the tail of list2 . And that would be necessary because list1 would be mutable. But Elixir knows list1 will never change, so it simply constructs a new list with a head of 4 and a tail of list1.

Elixir Basics - Types

A great reference for types: https://elixirschool.com/en/lessons/basics/basics/#basic-data-types

Collections

Once again, Elixir School is a great reference: https://elixirschool.com/en/lessons/basics/collections/

Annonimous Functions

Elixir is a functional language, therefore it is no surprise that functions are a basic type. An anonymous function is created using the fn keyword. ​ ​ fn ​ ​ parameter-list -> body ​ parameter-list -> body ... ​ ​ end ​ Think of fn … end as being a bit like the quotes that surround a string literal, except here we’re returning a function as a value, not a string. We can pass that function value to other functions. We can also invoke it, passing in arguments. At its simplest, a function has a parameter list and a body, separated by -> .

# list_concat exercise
iex(6)> list_concat = fn(a,b) -> a ++ b end
#Function<12.128620087/2 in :erl_eval.expr/5>

iex(7)> list_concat.([:a,:b], [:c, :d])    
[:a, :b, :c, :d]

# sum exercise
iex(8)> sum=&(&1 + &2 + &3)
#Function<18.128620087/3 in :erl_eval.expr/5>
iex(9)> sum.(1,2,3)
6

# tuple to list exercise
pair_tuple_to_list = fn(tuple) -> Tuple.to_list(tuple) end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment