Skip to content

Latest commit

 

History

History
157 lines (121 loc) · 4.34 KB

elixir.md

File metadata and controls

157 lines (121 loc) · 4.34 KB

Elixir

Elixir is among the most practical functional languages to date. It cherry-picked some of the best.

  • Clojure Features. — Efficient, Immutable Data Structures.
  • Optional lazy evaluation.
  • Protocols and records/structs.
  • Functional languages promote decoupling data from code.
    • Instead of class, we have modules which are collections of functions.
    • Instead of calling a method on an object call

Contrary to Clojure it also enjoys true tail call optimization and the pipeline operator.

Finally, it has a pleasant, modern, Ruby-like syntax, a rare gem among functional languages.

  • Atom

    • Maintains atom table.
    • String value is kept in table.
    • Atom holds a reference
    • The & sign is the capture operator. It turns function into lambda.
  • Higher order function

    • Functions in Elixir are first-class citizens.
    • This means that functions can be passed along as arguments to other functions. This also means that functions can return other functions as values.
  • List comprehension

    • See python

      • new_list = [expression for a member in iterable (if conditional)]
    • Being an FP language, Elixir has no loops

    • In fact, all of Elixir’s data structures are immutable

    • {[head | tail], {:atom, msg}} = {[1, 2, 3], {:atom, "PATTERN MATCHING FTW!"}}

    • [1, [2], [[3, 4], 5]] |> List.flatten |> Enum.map(fn x -> x * x * x end)

    • In object-oriented languages, we create objects. In Elixir, we spawn processes

    • Each process can communicate with other processes via message passing. The receiver of the message can choose to act upon the message if it understands it.

    • It is important to note that Elixir processes are not the same as operating system processes or threads. Elixir processes are very lightweight and are managed by the VM.

    • Message passing in process.

  • Tail Call Optimization

    • Instead of stack-based recursion, perform it like go to or jump instruction
defmodule Playground do
 for x <- [1, 2, 3] do
 x * x
 end

 for x <- [1, 2, 3], y <- [1, 2, 3], do: {x, y, x * y}

 table =
 for x <- 1..9, y <- 1..9, into: %{} do
 {{x, y}, x * y}
 end

 table =
 for x <- 1..9, y <- 1..9, x < y, into: %{} do
 {{x, y}, x * y}
 end
end

# defmodule Playground do
# Enum.map([1, 2, 3], fn x -> x * 2 end)
# [2, 4, 6]

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

#   Enum.reduce([1,2,3,4,5], 0, fn x, y -> x + y end)
#   Enum.reduce([1,2,3,4,5], 10, fn x, y -> x + y end)
# end

### x = 0, y = 1 => 1
### x = 1, y = 2 => 3
### x = 3, y = 3 => 6
### x = 6, y = 4 => 10
### x = 10, y = 5 => 15

### x = 10, y = 1 => 11
### x = 11, y = 2 => 13
### x = 13, y = 3 => 16
### x = 16, y = 4 => 20
### x = 20, y = 5 => 25

# defmodule Playground do
#   def start(n) do
#     start = :os.system_time(:seconds)
#     fib = getNumber(n)
#     finish = :os.system_time(:seconds)
#     diff = finish - start
#     IO.puts("Fib is #{fib}")
#     IO.puts("took: #{diff}")
#   end

#   def getNumber(n) when n < 0, do: :error
#   def getNumber(n), do: getNumber(n, 1, 0)
#   defp getNumber(0, _, result), do: result
#   defp getNumber(n, next, result), do: getNumber(n - 1, next + result, next)
# end

### getNumber(10) -> getNumber(10, 1, 0)
### getNumber(9, 1, 1) -> getNumber(8, 2, 1)
### getNumber(7, 3, 2) -> getNumber(6, 5, 3)
### getNumber(5, 8, 5) -> getNumber(4, 13, 8)
### getNumber(3, 21, 13) -> getNumber(2, 34, 21)
### getNumber(1, 55, 34) -> getNumber(0, _, 55) => 55

### getNumber(5) -> getNumber(4) + getNumber(3)
### (getNumber(3) + getNumber(2)) + (getNumber(2) + getNumber(1) [1])
### (1 + 0 + 1) + (1 + 0)  + (1 + 0) + 1 = 5
### getNumber(6) -> getNumber(5) [5] + getNumber(4)

# defmodule Playground do
#   def sum([]), do: 0

#   def sum([h | t]) do
#     h + sum(t)
#   end
# end

# def loop_forever do
#   loop_forever()
# end

### sum([1, 2, 3, 4, 5]) => h = 1, t = [2, 3, 4, 5]
### 1 + sum([2, 3, 4, 5]) => h = 2, t = [3, 4, 5]
### 1 + 2 + sum([3, 4, 5]) => h = 3, t = [4, 5]
### 1 + 2 + 3 + sum([4, 5]) => h = 4, t = [5]
### 1 + 2 + 3 + 4 + sum([5]) => h = 5, t = []
### 1 + 2 + 3 + 4 + 5 + sum([])

# defmodule Playground do
#   def print(0), do: :ok

#   def print(n) do
#     print(n - 1)
#     IO.puts(n)
#   end
# end

### print(10) => 10 -> print(9)
### print(9) => 9 -> print(8)
### ...
### print(2) => 2 -> print(1)
### print(1) => 1 -> print(0)
### print(0) => :ok