{"id":21589431,"url":"https://github.com/samh7/elixircheatsheet","last_synced_at":"2025-03-18T09:43:27.098Z","repository":{"id":226584711,"uuid":"721117521","full_name":"samh7/ElixirCheatSheet","owner":"samh7","description":null,"archived":false,"fork":false,"pushed_at":"2023-11-22T18:20:06.000Z","size":1758,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-01-24T16:14:09.279Z","etag":null,"topics":["cheatsheet","elixir"],"latest_commit_sha":null,"homepage":"","language":"Elixir","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/samh7.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null}},"created_at":"2023-11-20T11:48:47.000Z","updated_at":"2024-09-11T11:10:29.000Z","dependencies_parsed_at":"2024-03-08T12:06:33.115Z","dependency_job_id":null,"html_url":"https://github.com/samh7/ElixirCheatSheet","commit_stats":null,"previous_names":["samh7/elixircheatsheet"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/samh7%2FElixirCheatSheet","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/samh7%2FElixirCheatSheet/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/samh7%2FElixirCheatSheet/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/samh7%2FElixirCheatSheet/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/samh7","download_url":"https://codeload.github.com/samh7/ElixirCheatSheet/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":244198173,"owners_count":20414439,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cheatsheet","elixir"],"created_at":"2024-11-24T16:14:27.730Z","updated_at":"2025-03-18T09:43:27.071Z","avatar_url":"https://github.com/samh7.png","language":"Elixir","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Elixir Cheat Sheet\n---\n\n## Introduction\n\nElixir is a dynamic functional compiled language that runs over an Erlang Virtual Machine called BEAM.\n\u003cbr\u003e\n\nErlang and its BEAM is well known for running low-lattency, distributed and fault-tolerant applications\n\u003cbr\u003e\n\nElixir data types are immutable.\n\u003cbr\u003e\n\nIn Elixir a function is usually described with its arity (number of arguments), such as `is_boolean/1`\n\u003cbr\u003e\n\n## File Types\n---\n\n- `.exs` =\u003e Elixir Script File\n- `.ex` =\u003e Elixir Regular File\n- `.beam` =\u003e Compiled Elixir File\n\u003cbr\u003e\n\n## Compilating \u0026 Running Elixir Code\n\n- `elixir \u003cscript_file\u003e.exs` =\u003e run script code\n- `elixirc \u003cfile\u003e.ex` =\u003e compile a file into an `Elixir.\u003cFile\u003e.beam`\n\u003cbr\u003e\n\n## Elixr Convetions\n\n- `function foo return tuple` =\u003e the result of a foo funtion is usually {:ok, result} ot , {:error, reason}.\n- `function foo! may raise an error` =\u003e  the result of foo! is not wrapped in a tuple and may raise an exception.\n- **Exceptions/Erros** are not used to controlling flow.\n- Elixir uses **fail** **fast** idea and the supervision trees to control process health and if possible, restart processes.\n\u003cbr\u003e\n\n## Comments\n\n- `#` =\u003e Single line comments\n- No Multi-line comments\n\u003cbr\u003e\n\n## Code Documentation\n- `@moduledoc` =\u003e Module documentation\n- `@doc` =\u003e funtion doc.\n- `@spec` =\u003e function args/ return specification (types of the args and return of the function)\n- `@typedoc` =\u003e  type doc.\n- `@type` =\u003e type definition.\n- `@typep` =\u003e private type defintion\n\n### Eg.\n```elixir\ndefmodule Math d0\n    @moduledoc \"\"\"\n    provides math-related functions.\n    ## Examples\n    iex\u003e Math.sum(1,2)\n    3\n    \"\"\"\"\"\n    @spec sum(number, number) :: number\n    @doc\"\"\"\n    Calculates the sum of two numbers.\n    \"\"\"\n    def sum(a,b), do: a + b\nend\n\n```\n\u003cbr\u003e\n\n## Elixir Special Variables\n\n- `_` =\u003e unbound variable (discard)\n- `^var` =\u003e It pins the variable on its value and prevent any assignment to this variable when using pattern matching.\n    ### For Example\n```elixir\n    a = 1\n    b = 2\n    a = b # a now has a value of 2\n    a == b # return true or false\n    ^a = b = #pattern matches the two, if not equal, throws an error\n** (SyntaxError) iex:13:10: unexpected expression after keyword list. Keyword lists must always come last in lists and maps. Therefore, this is not allowed:\n\n    [some: :value, :another]\n    %{some: :value, another =\u003e value}\n\nInstead, reorder it to be the last entry:\n\n    [:another, some: :value]\n    %{another =\u003e value, some: :value}\n\nSyntax error after: ','\n    |\n 13 | %{age: 30, :name =\u003e \"Mary\"}\n    |          ^\n    (iex 1.15.7) lib/iex/evaluator.ex:294: IEx.Evaluator.parse_eval_inspect/4\n    (iex 1.15.7) lib/iex/evaluator.ex:187: IEx.Evaluator.loop/1\n    (iex 1.15.7) lib/iex/evaluator.ex:32: IEx.Evaluator.init/5\n    (stdlib 5.1.1) proc_lib.erl:241: :proc_lib.init_p_do_apply/3   \n``` \n- `|` =\u003e\n   1. used to update a single key in a map or a truct\n```elixir\n\n#The a key of the same name should already exist otherwise it errors\n# iex\u003e map = %{name: Alice}\n# iex\u003e map %{map} is not valid syntax you use it with the `|` operator to update a key\n\nmap = %{name: \"Alice\", age: 25}\nmap = %{map | name: \"Bob\"}\n\nstruct = %User{name: \"Alice\", age: 25}\nstruct = %{struct | name: \"Bob\"}\n```\n  2. To prepend an element to a list\n```elixir\n    list = [2,3,4]\n    list = [1 | list] # list now equals [1,2,3,4]\n```\n\u003cbr\u003e\n\n## Elixir/Erlang Virtual Machine inspection\n\n- `:observer.start` =\u003e Start a gui too for inspection\n- `:erlang.memory` =\u003e inspect memory\n- `:c.memory` =\u003e inspect memory\n```elixir\n    :c.memory\n    # [\n    #   total: 19262624,\n    #   processes: 4932168,\n    #   processes_used: 4931184,\n    #   system: 14330456,\n    #   atom: 256337,\n    #   atom_used: 235038,\n    #   binary: 43592,\n    #   code: 5691514,\n    #   ets: 358016\n    # ]\n```\n\u003cbr\u003e\n\n## Interactive Elxir/IEX\n\n- `iex` =\u003e open Interactive Elixir\n- `iex file` =\u003e open iex loading a file\n- `\u003cCtrl\u003ec + a` =\u003e close iex\n- `i \u003cobject\u003e` =\u003e information about an object\n- `h \u003cfunction/arity\u003e` =\u003e help for a function\n- `h \u003coperator/arity\u003e` =\u003e help for an operator\n- `s \u003cfunction/arity\u003e` =\u003e specification for a function\n- `s \u003coperator/arity\u003e` =\u003e specification for an operator\n- `t \u003cfunction/arity\u003e` =\u003e type for a function\n- `c \u003cfile\u003e` =\u003e Load and compile a .ex file\n\u003cbr\u003e\n\n# Basic Types\n---\n\u003cbr\u003e\n\n-  `1` =\u003e Integer\n-  `1_000` =\u003e integer, use `_` to make it easy to read\n-  `0x1F` =\u003e Hexadecimal integer\n-  `0b1010` =\u003e Binary integer, base 10  \n-  `0o777` =\u003e Octadecimal Integer\n- `1.0` =\u003e Float\n- `5.7e-2` =\u003e Floar exponent notation 0.057\n- `:atom` =\u003e atom/symbol\n- `true` =\u003e boolean (it is an atom)\n- `\u003c\u003c97::size(2)\u003e\u003e` =\u003e  bit string\n- `\u003c\u003c97,89\u003e\u003e` =\u003e Binary\n- `\"elixir\"` =\u003e string\n- {1,2,3} =\u003e tuple\n- [1,2,3] =\u003e list (actually a linked list)\n- `'elixir'` =\u003e char list\n- `[a: 5, b: 3]` =\u003e keyword list (short notation) `[a =\u003e 5, b =\u003e 3]` is not permited.\n- `[{:a, 5},{:b, 3}]`   keyword list (long notation)\n- `%{name: \"Mary\", age: 29}` =\u003e Map short notation (keys must be atoms).\n- `%{:name =\u003e \"Mary\", :age =\u003e 29}` =\u003e Map long notation.\n```elixir\n    # Keyword list(the short notation) must always come last. So if both short and long notation are used in the same map, the short notation should come last\n    %{:name =\u003e \"Mary\", age: 30} # Correct, does not error\n    %{name: \"Mary\", age: 30} # Correct, Does not error\n    %{age: 30, :name =\u003e \"Mary\"} # Errors\n        #** (SyntaxError) iex:13:10: unexpected expression after keyword list. Keyword lists must always come #last in lists and maps. Therefore, this is not allowed:\n        #[some: :value, :another]\n        #%{some: :value, another =\u003e value}\n        #Instead, reorder it to be the last entry:\n```\n- `self()` =\u003e Current Process id\n- `fn -\u003e :hello end` =\u003e Anonymous function\n- `make_ref()` =\u003e Create a new reference\n- `hd Port.list()` =\u003e get firt port\n- `is_nil/1`\n- `is_integer 1`\n- `is_float 4.6`\n- `is_number 7.8`\n- `is_atom :foo`\n- `is_boolean false`\n- `is_bitstring \u003c\u003c97:2\u003e\u003e`\n- `is_binary \u003c\u003c97, 98\u003e\u003e`\n- `is_list/1`\n- `is_tuple/1`\n- `is_map/1`\n- `is_pid self()`\n- `is_function(fn a, b -\u003e a + b end)` =\u003e function\n- `is_function(fn a, b -\u003e a + b end, 2)` =\u003e function with arity\n- `is_port hd Port.list()`\n- `is_reference make_ref()`\n- `Range.range?(1..3)`\n\u003cbr\u003e\n\n## Converting Types\n\u003cbr\u003e\n\n- `to_charlist(\"hello\")`\n- `to_string('hello')`\n- `Map.to_list(%{:a =\u003e 1, 2 =\u003e :b})` =\u003e map to list of tuples\n\u003cbr\u003e\n\n## Number Operators\n\u003cbr\u003e\n\n- `10/2 =\u003e 5.0` =\u003e always returns a float\n- `div(10, 2) =\u003e 5` =\u003e Integer division\n- `rem(10, 3) =\u003e 1` =\u003e Modulus operation\n- `round(3.58) =\u003e 4` =\u003e float round\n- `trunc(3.58) =\u003e 3` =\u003e float trunc\n\u003cbr\u003e\n\n## Operators\n`==`, `!=`, `===` =\u003e strict equal (integer with float), `!==` =\u003e strict different (inetger with float), `\u003c`, `\u003c=`, `\u003e`, `\u003e=`, `\u0026\u0026` =\u003e truthy and (t-and), `||` =\u003e t-or, `!`, `and` =\u003e boolean and (b-and), `or` =\u003e b-or, `not` =\u003e b-not\n\n### \u003cu\u003eNOTE\u003c/u\u003e\n\u003cbr\u003e\n\nIt's possible to compare different data types and that's the sorting order: `number \u003c atom \u003c reference \u003c functions\u003c port \u003c pod \u003c tuple \u003c list \u003c bit string` (narf, pptlb)\n\u003cbr\u003e\n\n## Pipe Operator\n\u003cbr\u003e\n\n-   `|\u003e` =\u003e Pipe Operator. Passes a value as the first argument of the function following it\n```elixir\n    1.100\n    |\u003e Stream.map(\u0026(\u00261 * 3)) \n    |\u003e Stream.filter(\u0026(rem(\u00261,2) != 0))\n    |\u003e Enum.sum\n    # =\u003e 7500    \n```\n\u003cbr\u003e\n\n## Pattern Matching\n\n`=` =\u003e is not just an assignment operator, but a Match Operator. It matches variables from the right side to the left based on patterns defined by the left one. If a pattern does not match a `MatchError` is raised.\n\n```elixir\n    [a, b, 10] = [0,1,10] #does not error instead, assigns values 0 and 1 to variables a and b respectively.\n    \n    %{a: 10, :b =\u003e 20 } =\u003e %{:a =\u003e 10, b: 20}\n```\n\u003cbr\u003e \nBut, for variables, is will most likely be an assignment operator:\n\n```elixir\n    a = 1\n    b = 2\n    a = b # a now is equal to 1\n```\n\u003cbr\u003e\n\nWe therefore use a pin operator `^` to pattern match variables:\n\n```elixir\n    a = 1\n    b = 10\n    ^a = b #errors\n```\n\u003cbr\u003e\n\n```elixir\n#To pattern match a single item from a struct or a map do:\nmap = %{name: \"Alice\", age: 25}\n%{name: name} = map\n```\n\n```elixir\n#empty maps/ structs always match for any map/struct respectively\nmap = %{name: \"Alice\", age: 25}\n%{} = map # does not error\n```\n\u003cbr\u003e\n\n### So in other words:\n- non variables on the left side will be used to restrict a pattern to match\n- variables using the pin operator on the left side will have its value to be used to restrict a pattern to match\n- variables on the left side will be assigned with right side values\n\u003cbr\u003e\n\n## Match Operator Limitation\n\u003cbr\u003e\n\nYou cannot make function calls on the left side of a match.\n- `length([1, [2], 3]) = 3 #=\u003e ** (CompileError) illegal pattern`\n\u003cbr\u003e\n\n## Custom Operators\n---\n\u003cbr\u003e\n\nYou can customize an Elixir Operator.\nexample:\n```elixir\n    1 + 2 # =\u003e 3\n    defmodule WrongMath do\n        def a + b do\n            {a, b}\n        end\n    end\n    import WrongMath\n    import Kernel, except: [+: 2]\n    1 + 2 #=\u003e {1, 2}\n```\n\n## Sigils\n---\n\n- `~r` =\u003e regular expression (modifires: `i`)\n- `~r/hello/i` =\u003e `i` modifies to case insensitive\n- `~w` =\u003e list of a string of words (eg. `~w[foo bar]`)\n- `~w[foo bar]c` =\u003e `c` modifies list of char lists\n- `~w[foo bar]a` =\u003e `c` modifies to list ot atoms\n```elixir\n~w(one two three)   #=\u003e [\"one\", \"two\", \"three\"]\n~w(one two threee)c #=\u003e ['one', 'two', 'three']\n~w(one two three)a  #=\u003e [:one, :two, :three]\n```\n## Bit Strings\n---\n\n- `\u003c\u003c97::4\u003e\u003e` =\u003e short notation with 4 bits\n- `\u003c\u003c97::size(4)\u003e\u003e` =\u003e long notation with 4 bits\n- `byte_size(\u003c\u003c5::4\u003e\u003e)` =\u003e bit string byte size\n  \n## Binaries\n---\n\nBinaries are 8 bit multiple Bit Strings. Binaries are 8 bits by default.\n\n- `\u003c\u003c97\u003e\u003e` =\u003e Shirt notation with 8 bits.\n- `\u003c\u003c97::size(8)\u003e\u003e` =\u003e Long notation with 8 bits.\n- `\u003c\u003e` =\u003e concatenate binaries/strings\n\n## Strings\n---\n\nString is a binary of code points where all elements are valid characters.\n\nStrings are sorrounded by double quotes and are encoded in `UTF-8` by default.\n\n- `\"hello\"` =\u003e string\n- `\u003c\u003c97, 98\u003e\u003e` =\u003e string \"ab\"\n- `\u003c\u003c?a, ?b\u003e\u003e` =\u003e string \"ab\"\n- `?a` =\u003e 97\n- `?b` =\u003e 98\n- `\"hello #{:world}\"` =\u003e string interpolation for \"hello world\"\n- `String.length(\"hello\") #=\u003e5`\n- `String.upcase(\"hello\") #=\u003e \"HELLO\"`\n- `\"\"\"(begin) multi-line string (end)\"\"\"`\n\n### Performance for Strings:\n\ncheap functions =\u003e `byte_size(\"hello\")`\nexpensive functions =\u003e `String.length(\"hello\")`\n\n## Tuples \n---\n\nTuple is a list that is stored contiguously in memory.\n- `{:ok, \"hello\"}`\n- `tuple_size({:ok, \"hello\"})` =\u003e tuple size (cheap function)\n- `elem({:ok, \"hello\"}, 0)` =\u003e get tuple element by index (cheap function)\n- `put_elem({:ok, \"hello\"}, 1, \"world\")` (expensive function)\n  \n## Lists\n---\n\nLists implements Enumerables protocol.\n\nList is a linked list structure where each element points to the next one in memory. When subtraction just the first ocurrence will be removed.\n\n- `[:ok, \"hello\"]`\n- `[97 | [1, 6, 9]]` =\u003e prepend (expensive function)\n- `[1, 5] ++ [3, 9] # [1, 5, 3, 9]` =\u003e concatenation (expensive function)\n- `[1, 2, 3, 4, 5, 6] -- [3,4,10,13] # [1,2,5,6]` =\u003e Keep all elements in the first list execpt for all the commont elements between the two lists and discard the rest in the second list.\n- `hd([1, 5, 7]) #=\u003e 1` =\u003e head (cheap function)\n- `tl([1,5,7]) #=\u003e [5,7]` =\u003e  tails (cheap function)\n- `:foo in [:foo, :bar] #=\u003e true` =\u003e in operator (expensive function)\n- `length([1,5])` =\u003e length of list (expensive function)\n\n## Char List\n---\n\nA Char List is a List of code points where all elements are valid characters. Char Lists are surrounded by single-quote and are ***usually used as arguments to some old Erlang code***.\n\n- `ab` =\u003e Char list\n- `[97, 98]` =\u003e 'ab'\n- `[?a,?b]` =\u003e 'ab'\n- `?a` =? 97\n-  `'hello' ++ 'world' #helloworld` =\u003e Concatenation\n- `'hello' -- 'world' #hel` =\u003e Keep all elements in the first char list execpt for all the commont elements between the two lists and discard the rest in the second char list.\n- `?l in 'hello' #true` =\u003e in operator\n- `'length('hello')'`\n- `[?H | 'ello']`\n\n## Keyword Lists\n---\n\nKeyword list is a list of tuples where first elements are atoms. When fetching by key the first match will return. If a keyword list is the last argument of a function the square brackets [ are optional.\n\n- `[{:a, 6} | [b: 7]] # [a: 6, b: 7]` =\u003e prepend\n- `[a: 5] ++ [a: 7] # [a: 5, a: 7]`\n- `([a: 5, a: 7])[:a] # 5` =\u003e fetch by key\n- `length([a: 5, b: 7])`\n  \n  ### \u003cu\u003eNote\u003cu\u003e\n\n- `[{:a, 6} | [b: 7]]` =\u003e `[a: 6, b: 7]`\n- `[[a: 6] | [b: 7]]` =\u003e `[[a: 6], {:b, 7}]` \n\n## Maps\n---\n\nMaps implements Enumerable Protocol.\nMap holds a key value structure.\n- `%{name: \"Mary\", age: 29}[:name] #=\u003e \"Mary`\n- `%{name: \"Mary\", age: 29}[:born] #=\u003e nil`\n- `%{name: \"Mary\", age: 29}.name #=\u003e \"Mary`\n- `%{name: \"Mary\", age: 29}.name #=\u003e ** (KeyError)`\n- `map_size(%{name: \"Mary\"}) #=\u003e 1`\n  \n## Structs\n---\nStructs are built on top of maps\n`defstruct` =\u003e define a struct\n\n```elixir\ndefmodule User do\n  defstruct name: \"John\", age: 27\nend\njohn = %User{} #=\u003e %User{age: 27, name: \"John\"}\nmary = %User{name: \"Mary\", age: 25} #=\u003e %User{age: 25, name: \"Mary\"}\nmeg = %{john | name: \"Meg\"} #=\u003e %User{age: 27, name: \"Meg\"}\nbill = Map.merge(john, %User{name: \"Bill\", age: 23}) #=\u003e %User{name: \"Bill\", age: 23}\n\njohn.name #=\u003e John\njohn[:name] #=\u003e ** (UndefinedFunctionError) undefined function: User.fetch/2\nis_map john #=\u003e true\njohn.__struct__ #=\u003e User\nMap.keys(john) #=\u003e [:__struct__, :age, :name]\n```\n\n## Ranges\n---\n\nRanges are `struct`\n- `range = 1..10`\n- `Enum.reduce(1..3, 0, fn i, acc -\u003e i + acc end) #=\u003e 6`\n- `Enum.count(range) #=\u003e 10`\n- `Enum.member?(range, 11) #=\u003e false`\n\n## Protocols\n---\n\n- `defprotocol Foo do ... end` =\u003e define protocol `Foo`\n- `defimpl Blank, for: Integer do ... end` =\u003e implement that protocol `Integer`\n- Here are all native data types that you can use: `Atom`, `BitString`, `Float`, `Function`, `Integer`, `List`, `Map`, `PID`, `Port`, `Reference`, `Tuple`.\n```elixir\ndefprotocol Blank do\n  @doc \"Returns true if data is considered blank/empty\"\n  def blank?(data)\nend\n\ndefimpl Blank, for: Integer do\n  def blank?(_), do: false\nend\n\ndefimpl Blank, for: List do\n  def blank?([]), do: true\n  def blank?(_),  do: false\nend\n\ndefimpl Blank, for: Map do\n  def blank?(map), do: map_size(map) == 0\nend\n\n\n# Structs do not share Protocol implementations with Map.\ndefimpl Blank, for: User do\n  def blank?(_), do: false\nend\n\ndefimpl Blank, for: Atom do\n  def blank?(false), do: true\n  def blank?(nil),   do: true\n  def blank?(_),     do: false\nend\n\nBlank.blank?(0) #=\u003e false\nBlank.blank?([]) #=\u003e true\nBlank.blank?([1, 2, 3]) #=\u003e false\nBlank.blank?(\"hello\") #=\u003e ** (Protocol.UndefinedError)\n```\n```elixir\n# You can also implement a Protocol for Any. And in this case you can derive any Struct\n\ndefimpl Blank, for: Any do\n  def blank?(_), do: false\nend\n\ndefmodule DeriveUser do\n  @derive Blank\n  defstruct name: \"john\", age: 27\nend\n```\n\nElixir built-in most common used protocols: `Enumerable`, `String.Chars`, `Inspect`.\n\n## Nested data Structures\n- `put_in/2` =\u003e Puts a value in a nested structure via the given path.\n- `update_in/2` =\u003e Updates a nested structure via the given path.\n- `get_and_update_in/2` =\u003e Gets a value and updates a nested data structure via the given\npath.\n```elixir\nusers = [\n  john: %{name: \"John\", age: 27, languages: [\"Erlang\", \"Ruby\", \"Elixir\"]},\n  mary: %{name: \"Mary\", age: 29, languages: [\"Elixir\", \"F#\", \"Clojure\"]}\n]\nusers[:john].age #=\u003e 27\n\nusers = put_in users[:john].age, 31\nusers = update_in users[:mary].languages, \u0026List.delete(\u00261, \"Clojure\")\n```\n\n## Enums and Streams\n---\n\nLists and Maps are Enumerables\n`Enum` module perform **eager** operations, meanwhile `Stream` module perform **lazy** operations.   \n```elixir\n# eager Enum\n1..100 |\u003e Enum.map(\u0026(\u00261 * 3)) |\u003e Enum.sum #=\u003e 15150\n\n# lazy Stream\n1..100 |\u003e Stream.map(\u0026(\u00261 * 3)) |\u003e Enum.sum #=\u003e 15150\n```\n\n## do/end Keyword List and Block Syntax\n---\n\nIn Elixir **Keyword List** syntax or do/end **Block** syntax:\n```elixir\nsky = :gray\n\nif sky == :blue do\n  :sunny\nelse\n  :cloudy\nend\n\nif sky == :blue, do: :sunny, else: :cloudy\n\nif sky == :blue, do: (\n  :sunny\n), else: (\n  :cloudy\n)\n```\n\n## Conditional Flows (if/else/case/cond)\n\n### if/else\n\n```elixir\nsky = :gray\nif sky == :blue, do: :sunny, else: :cloudy\n```\n\n### unless / else\n\n```elixir\nsky = :gray\nunless sky != :blue, do: :sunny, else: :cloudy\n```\n\n### case / when\n\n```elixir\nsky = {:gray, 75}\ncase sky, do: (\n  {:blue, _}         -\u003e :sunny\n  {_, t} when t \u003e 80 -\u003e :hot\n  _                  -\u003e :check_wheather_channel\n)\n```\n\nOn **when guards** short-circuiting operators \u0026\u0026, || and ! are not allowed.\n\n### cond\n\n`cond` is equivalent as `if/else-if/else` statements.\n\n```elixir \nsky = :gray\ncond do: (\n  sky == :blue -\u003e :sunny\n  true         -\u003e :cloudy\n)\n```\n\n## The `with` macro\n---\n\n- `with` =\u003e macro to combine multiple match clauses\n- `\u003c-` =\u003e a matching clause, on the left\n- `=` =\u003e bare expression is allowed\n- `else` =\u003e if some matching clause fails\n\n\u003c!-- \u003c- vs =  vs \u003c=--\u003e\n\n```elixir\nopts = %{width: 10, height: 20}\nwith {:ok, width} \u003c- Map.fetch(opts, :width),\n     {:ok, height} \u003c- Map.fetch(opts, :height) do\n  {:ok, width * height}\nelse\n  :error -\u003e\n    {:error, :wrong_data}\nend\n\nopts = %{width: 10, height: 20}\nwith {:ok, width} \u003c- Map.fetch(opts, :width),\n     {:ok, height} \u003c- Map.fetch(opts, :height) do\n  {:ok, width * height}\nelse\n  :error -\u003e\n    {:error, :wrong_data}\nend\n\n#=\u003e {:ok, 200}\n```\n\n## Recursion\n---\n\nThere is traditional no for loop in Elixir, due to Elixir immutability There is a macro `for` that it's also called as `Comprehension` but it works differently from a traditional for loop. If you want a simple loop iteration you'll need to use `recursion`:\n```elixir\ndefmodule Logger do\n  def log(msg, n) when n \u003c= 0, do: ()\n  def log(msg, n) do\n    IO.puts msg\n    log(msg, n - 1)\n  end\nend\nLogger.log(\"Hello World!\", 3)\n# Hello World!\n# Hello World!\n# Hello World!\n```\n\nIn functional programming languages map and reduce are two major algorithm concepts. They can be implemented with recursion or using the `Enum` module.\n\n`reduce` will reduce the array into a single element.\n\n```elixir \ndefmodule Math do\n  def sum_list(list, sum \\\\ 0)\n  def sum_list([], sum), do: sum\n  def sum_list([head | tail], sum) do\n    sum_list(tail, head + sum)\n  end\nend\nMath.sum_list([1, 2, 3]) #=\u003e 6\n\nEnum.reduce([1, 2, 3], 0, \u0026+/2) #=\u003e 6\n```\n\nmap modifies an existing array (new array with new modified values):\n\n```elixir\ndefmodule Math do\n  def double([]), do: []\n  def double([head | tail]) do\n    [head * 2 | double(tail)]\n  end\nend\nMath.double([1, 2, 3]) #=\u003e [2, 4, 6]\n\nEnum.map([1, 2, 3], \u0026(\u00261 * 2)) #=\u003e [2, 4, 6]\n```\n\n## Comprehension -\u003e the for loop\n\n`Comprehension`  is a syntax sugar for the very powerful `for special form`. You can have **generators** and **filters** in that.\n- `for` =\u003e `comprehension`\n- `-\u003e` =\u003e `generators`\n- `:into` =\u003e Change return to another `Collectable` type.\n  \nYou can iterate over `Enumrable` whats makes so close to a regular `for` loop on other languages:\n```elixir\nfor n \u003c- [1, 2, 3, 4], do: n * n\n#=\u003e [1, 4, 9, 16]\n```\n\nYou can also iterate over multiple `Enumerable` and then create a combination between them:\n\n```elixir\nfor i \u003c- [:a, :b, :c], j \u003c- [1, 2], do:  {i, j}\n#=\u003e [a: 1, a: 2, b: 1, b: 2, c: 1, c: 2]\n```\n\nYou can pattern match each element\n\n```elixir\nvalues = [good: 1, good: 2, bad: 3, good: 4]\nfor {:good, n} \u003c- values, do: n * n\n#=\u003e [1, 4, 16]\n```\n\nGenerators use `-\u003e` and they have on the right an `Enumerable`  and on the left a pattern matchable element variable.\n\nYou can have **filters** to filter **truthy elements**:\n```elixir\nfor dir  \u003c- [\".\", \"/\"],\n    file \u003c- File.ls!(dir),\n    path = Path.join(dir, file),\n    File.regular?(path) do\n  \"dir=#{dir}, file=#{file}, path=#{path}\"\nend\n#=\u003e [\"dir=., file=README.md, path=./README.md\", \"dir=/, file=.DS_Store, path=/.DS_Store\"]\n```        \n\nYou can `:into` to change the return type:\n\n```elixir\nfor k \u003c- [:foo, :bar], v \u003c- 1..5, into: %{}, do: {k, v}\n#=\u003e %{bar: 5, foo: 5}\nfor k \u003c- [:foo, :bar], v \u003c- 1..5, into: [], do: {k, v}\n#=\u003e [foo: 1, foo: 2, foo: 3, foo: 4, foo: 5, bar: 1, bar: 2, bar: 3, bar: 4, bar: 5]\n```\n\n## Anonymous Functions\n- `fn` =\u003e define functions\n- `-\u003e` =\u003e one line function definition\n- `.` =\u003e call a function\n- `when` =\u003e guards\n\n```elixir\nadd = fn a, b -\u003e a + b end\nadd.(4, 5) #=\u003e 9\n```\n\nWe can have multiple clauses and guards inside functions.\n\n```elixir\ncalc = fn\n  x, y when x \u003e 0 -\u003e x + y\n  x, y -\u003e x * y\nend\ncalc.(-1, 6) #=\u003e -6\ncalc.(4, 5) #=\u003e 9\n```\n\n## Modules And Named Functions\n- `defmodule`\n- `def` =\u003e functions (inside Modules)\n- `defp` =\u003e private functions (\")\n- `when` =\u003e guard\n- `@` =\u003e module attribute\n- `__info__(:functions)` =\u003e list functions inside a module\n- `defdelagate` =\u003e delegate functions\n```elixir\ndefmodule Math do\n  def sum(a, b) when is_integer(a) and is_integer(b), do: a + b\nend\n\nMath.sum(1, 2) #=\u003e 3\n\nMath.__info__(:functions) #=\u003e [sum: 2]\n```\n\nModule attribute works as constants, evaluated at compilation time:\n\n```elixir\ndefmodule Math do\n  @foo :bar\n  def print, do: @foo\nend\n\nMath.print #=\u003e :bar\n```\n\nSpecial Module attributes:\n\n`@nsv`, `@moduledoc`,`@doc`,`@behaviour`, `@before_compile`\n\n## Default Argument\n```elixir\ndefmodule Concat do\n  def join(a, b, sep \\\\ \" \") do\n    a \u003c\u003e sep \u003c\u003e b\n  end\nend\n\nIO.puts Concat.join(\"Hello\", \"world\")      #=\u003e Hello world\nIO.puts Concat.join(\"Hello\", \"world\", \"_\") #=\u003e Hello_world\n```\n\nDefault values are **evaluated runtime**.\n\nSo this is correct syntax:\n\n```elixir\ndefmodule DefaultTest do\n  def dowork(x \\\\ IO.puts \"hello\") do\n    x\n  end\nend\nDefaultTest.dowork #=\u003e :ok\n# hello\nDefaultTest.dowork 123 #=\u003e 123\nDefaultTest.dowork #=\u003e :ok\n# hello\n```\n\nFunction with multiple clauses and a default value requires a function head where default values are set:\n\n```elixir\ndefmodule Concat do\n  def join(a, b \\\\ nil, sep \\\\ \" \") # head function\n\n  def join(a, b, _sep) when is_nil(b) do\n    a\n  end\n\n  def join(a, b, sep) do\n    a \u003c\u003e sep \u003c\u003e b\n  end\nend\n\nIO.puts Concat.join(\"Hello\")               #=\u003e Hello\nIO.puts Concat.join(\"Hello\", \"world\")      #=\u003e Hello world\nIO.puts Concat.join(\"Hello\", \"world\", \"_\") #=\u003e Hello_world\n```\n\n## Function Capturing\n- `\u0026` =\u003e Function capturing\n- `\u00261` =\u003e first argument\n- `\u00262` =\u003e Secong argument and so on.\n\n`\u0026` could be used with a module function.\n\nWhen capturing you can use the function/operator with its arity.\n\n```elixir\n\u0026(\u00261 * \u00262).(3, 4) #=\u003e 12\n(\u0026*/2).(3, 4) #=\u003e 12\n\n(\u0026Kernel.is_atom(\u00261)).(:foo) #=\u003e true\n(\u0026Kernel.is_atom/1).(:foo) #=\u003e true\n(\u0026{:ok, [\u00261]}).(:foo) #=\u003e {:ok, [:foo, :bar]}\n(\u0026[\u00261, \u00262]).(:foo, :bar) #=\u003e [:foo, :bar]\n(\u0026[\u00261 | [\u00262]]).(:foo, :bar) #=\u003e [:foo, :bar]\n#####################\nadd3 = (\u0026(\u00261+\u00262))\nadd3.(1,2)\n```\n\n\n## Behaviours\n---\n\n- `@callbacks` =\u003e defines a function to be implemented by other modules\n- `::` =\u003e Separates the function defintion to its return type\n\n```elixir\ndefmodule Parser do\n  @callback parse(String.t) :: any\n  @callback extensions() :: [String.t]\nend\n\ndefmodule JSONParser do\n  @behaviour Parser\n\n  def parse(str), do: # ... parse JSON\n  def extensions, do: [\"json\"]\nend\n```\n\n## Exceptions/Errors =\u003e raise/try/rescue\n---\n\nExceptions/Errors in Elixir are `structs`\n- `raise \"oops\" #=\u003e ** (RuntimeError) oops\n- `raise ArgumentError #=\u003e ** (ArgumentError) argument error`\n- `raise ArgumentError, message: \"oops\" #=\u003e ** (ArgumentError) oops`\n- `defexception` =\u003e define an exception\n- `try/rescue` =\u003e catches an error\n- `throw/try/catch` =\u003e  can be used as circuit breaking, but should be avoided\n- `exit(\"my reason\")` =\u003e exiting current process\n- `after` =\u003e  ensures some resource is cleaned up even if an exception was raised\n\n```elixir\ndefmodule MyError do\n  defexception message: \"default message\"\nend\n\nis_map %MyError{} #=\u003e true\nMap.keys %MyError{} #=\u003e [:__exception__, :__struct__, :message]\n\nraise MyError #=\u003e ** (MyError) default message\nraise MyError, message: \"custom message\" #=\u003e ** (MyError) custom message\n```\n\nYou can rescue an error with:\n```elixir\ndefmodule MyError do\n  defexception message: \"default message\"\nend\n\nis_map %MyError{} #=\u003e true\nMap.keys %MyError{} #=\u003e [:__exception__, :__struct__, :message]\n\nraise MyError #=\u003e ** (MyError) default message\nraise MyError, message: \"custom message\" #=\u003e ** (MyError) custom message\n```\n\n`throw/catch` sometime is used for circuit breaking, but you can usually use another better way:\n\n```elixir\ntry do\n  Enum.each -50..50, fn(x) -\u003e\n    if rem(x, 13) == 0, do: throw(x)\n  end\n  \"Got nothing\"\ncatch\n  x -\u003e \"Got #{x}\"\nend\n#=\u003e \"Got -39\"\n\nEnum.find -50..50, \u0026(rem(\u00261, 13) == 0)\n#=\u003e -39\n```\n\n`exit` can be caught but this is rare in Elixir:\n```elixir\ntry do\n  exit \"I am exiting\"\ncatch\n  :exit, _ -\u003e \"not really\"\nend\n#=\u003e \"not really\"\n```\n\nYou can ommit `try` inside functions and use `rescue`, `catch`, `after` directly:\n\n```elixir\ndef without_even_trying do\n  raise \"oops\"\nafter\n  IO.puts \"cleaning up!\"\nend\n```\n\n## IO\n---\n\n- `IO.puts/1 \"Hello\"` =\u003e prints to stdout\n- `IO.puts :stderr, \"Hello\"` =\u003e print to stderr\n- `IO.gets \"yes/no: \"` =\u003e reads an user input\n\n##StringIO\n---\n\n- `{:ok, pid} = StringIO.open(\"my-file.md\")` =\u003e open a file\n-  `IO.read(pid, 2) #=\u003e \"he\"` =\u003e read first 2 lines\n\n## File\n---\n\n- `{:ok, file} = File.open \"hello\", [:write]` =\u003e open a file for writing.\n- `IO.binwrite(file, \"world\")` =\u003e Writes into file\n- `File.close(file)` =\u003e close file\n- `File.read(\"my-file.md\")` =\u003e read a file\n- `File.stream!(\"my-file.md\") |\u003e Enum.take(10)` =\u003e read the first 10 lines\n```elixir\n{:ok, file} = File.open \"my-file.md\", [:write]\nIO.binwrite file, \"hello world\"\nFile.close file\nFile.read \"my-file.md\" #=\u003e {:ok, \"hello world\"}\n```\n\n## Path\n---\n\n- `Path.join` =\u003e joins\n- `Path.expand(\"~/hello\")` =\u003e expand full path\n\n## Process, Tasks and Agents\n---\n\nProcess in Elixir has the same concept as threads in a lot of other languages,  but extremely lightweight in terms of memory and CPU. They are isolated from each other and communicate via message passing.\n- `spawn/1` =\u003e fork a process\n- `self()` =\u003e current process\n- `Process.alive?(pid)` =\u003e check if process is still alive\n- `send/2` =\u003e send message to another process\n- `receive/1` =\u003e receive message from another process\n- `after` =\u003e receive option to work with after timetout.\n- `flush()` =\u003e prints out all messages received\n- `spawn_link/1` =\u003e forks a process and link them , so failures are proagated.\n- `Task.start/1`= \u003e Starts a task\n- `Task.start_link/1` =\u003e starts a task and links them to current process\n- `Process.register(pid, :foo)` =\u003e register a name for a process\n\nThe idea is to have a supervisor that `spawn_link` new processes and when they fail the supervisor will restart them.\nThis is the basics for **Fail Fast** and Fault **Tolerant** in Elixir.\n\nTasks are used in supervision trees.\n```elixir \nparent = self()\n\nspawn_link(fn -\u003e send(parent, {:hello, self()}) end)\nreceive do: ({msg, pid} -\u003e \"#{inspect pid} =\u003e #{msg}\"), after: (1_000 -\u003e \"nothing after 1s\")\n\nTask.start_link(fn -\u003e send(parent, {:hello, self()}) end)\nreceive do: ({msg, pid} -\u003e \"#{inspect pid} =\u003e #{msg}\"), after: (1_000 -\u003e \"nothing after 1s\")\n\nflush()\n```\n\n```elixir \n\n```\n\n**State** can be stored in processes or using its abstraction: `Agent`.\n\nManual implementation of a storage using Elixir Processes:\n```elixir\ndefmodule KV do\n  def start_link do\n    Task.start_link(fn -\u003e loop(%{}) end)\n  end\n\n  defp loop(map) do\n    receive do\n      {:get, key, caller} -\u003e\n        send caller, Map.get(map, key)\n        loop(map)\n      {:put, key, value} -\u003e\n        loop(Map.put(map, key, value))\n    end\n  end\nend\n{:ok, pid} = KV.start_link\n\nsend pid, {:put, :hello, :world}\nsend pid, {:get, :hello, self()}\nflush() #=\u003e :world\n```\n\nImplementation of a storage using `Agent`:\n```elixir\n{:ok, pid} = Agent.start_link(fn -\u003e %{} end)\nAgent.update(pid, fn map -\u003e Map.put(map, :hello, :world) end)\nAgent.get(pid, fn map -\u003e Map.get(map, :hello) end)\n```\n\n## alias, require, import and use\n---\n\nIn order to facilitate code reuse Elixir has: `alias`, `require`, `import` (directives) and `use` (macro).\n  - `alias Foo.Bar, as: Bar` =\u003e alias module, so Bar can be called instead of Foo.Bar\n  - `alias Foo.Bar` =\u003e `as` is optional on alias\n  - `require Foo` =\u003e  requires and import functions from Foo so they can be called without the `Foo.` prefix\n  - `import List, only: [duplicate: 2]` =\u003e only option\n  - `import List, expect: [duplicate: 2]` =\u003e except option\n  - `import List, only: :macros ` =\u003e import only macros\n  - `import List, only: :functions` =\u003e import only functions\n  - `use Foo` =\u003e  invokes the custom code defined in Foo as an extension point\n  - `alias MyApp.{Foo, Bar, Baz} ` =\u003e multiple aliases\n  - `require MyApp.{Foo, Bar, Baz}` =\u003e  multiple require\n  - `import MyApp.{Foo, Bar, Baz}` =\u003e multiple import\n  \n  All modules are defines inside `Elixir` namespace but it can be omitted for convenience.\n  `alias`, `require` and `import` are lexically scoped, which means that it will be valid just inside the scope it was defined. This is not a global scope.\n\n  `require` is usually used to require Elixir macro code:\n\n  ```elixir\n  Integer.is_odd(3) #=\u003e ** (CompileError): you must require Integer before invoking the macro Integer.is_odd/1\n  require Integer\n  Integer.is_odd(3) #=\u003e true\n  ```\n`use` call `__using__` when the module is being used:\n\n```elixir\ndefmodule Fruit do\n  defmacro __using__(option: option) do\n    IO.puts \"options=#{inspect option}\"\n    quote do: IO.puts \"Using Fruit module\"\n  end\nend\n\ndefmodule Meal do\n  use Fruit, option: :hello\nend\n###Result###\n#options=:hello\n#Using Fruit module\n#:ok\n```\n\n## Meta Programming\n---\n\n- `quote` =\u003e shows AST (Abstract Syntax Tree)\n```elixir\nquote do: 2 * 2 == 4\n#=\u003e {\n#=\u003e   :==,\n#=\u003e   [context: Elixir, import: Kernel],\n#=\u003e   [\n#=\u003e     {\n#=\u003e       :*,\n#=\u003e       [context: Elixir, import: Kernel],\n#=\u003e       [2, 2]\n#=\u003e     },\n#=\u003e     4\n#=\u003e   ]\n#=\u003e }\n```\n\n## Erlang Libraries\n---\n\n- :crypto =\u003e crypto functions like `:crypto.hash/2`\n- `:io` =\u003e io functions like `:io.format/2`\n- `:digraph` =\u003e deal with digraphs\n- `:ets` =\u003e large data structure in memory\n- `:dets` =\u003e large data structure on disk\n- `:math` =\u003e math functions like `:math.pi/0`\n- `:queue` =\u003e first-in first-out structure\n- `:rand` =\u003e rand functions like `:rand.uniform/0`\n- `:zip` =\u003e handle zip files\n- `:zlib` =\u003e handle gzip files","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsamh7%2Felixircheatsheet","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsamh7%2Felixircheatsheet","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsamh7%2Felixircheatsheet/lists"}