Warning, /frameworks/syntax-highlighting/autotests/folding/learnelixir.exs.fold is written in an unsupported language. File is not indexed.
0001 # Original: https://learnxinyminutes.com/docs/elixir/ 0002 0003 # Single line comments start with a number symbol. 0004 0005 # There's no multi-line comment, 0006 # but you can stack multiple comments. 0007 0008 # To use the elixir shell use the `iex` command. 0009 # Compile your modules with the `elixirc` command. 0010 0011 # Both should be in your path if you installed elixir correctly. 0012 0013 ## --------------------------- 0014 ## -- Basic types 0015 ## --------------------------- 0016 0017 # There are numbers 0018 3 # integer 0019 0x1F # integer 0020 3.0 # float 0021 0022 # Atoms, that are literals, a constant with name. They start with `:`. 0023 :hello # atom 0024 0025 # Tuples that are stored contiguously in memory. 0026 <beginfold id='1'>{</beginfold id='1'>1,2,3<endfold id='1'>}</endfold id='1'> # tuple 0027 0028 # We can access a tuple element with the `elem` function: 0029 elem<beginfold id='2'>(</beginfold id='2'><beginfold id='1'>{</beginfold id='1'>1, 2, 3<endfold id='1'>}</endfold id='1'>, 0<endfold id='2'>)</endfold id='2'> #=> 1 0030 0031 # Lists that are implemented as linked lists. 0032 <beginfold id='3'>[</beginfold id='3'>1,2,3<endfold id='3'>]</endfold id='3'> # list 0033 0034 # We can access the head and tail of a list as follows: 0035 <beginfold id='3'>[</beginfold id='3'>head | tail<endfold id='3'>]</endfold id='3'> = <beginfold id='3'>[</beginfold id='3'>1,2,3<endfold id='3'>]</endfold id='3'> 0036 head #=> 1 0037 tail #=> [2,3] 0038 0039 # In elixir, just like in Erlang, the `=` denotes pattern matching and 0040 # not an assignment. 0041 # 0042 # This means that the left-hand side (pattern) is matched against a 0043 # right-hand side. 0044 # 0045 # This is how the above example of accessing the head and tail of a list works. 0046 0047 # A pattern match will error when the sides don't match, in this example 0048 # the tuples have different sizes. 0049 # {a, b, c} = {1, 2} #=> ** (MatchError) no match of right hand side value: {1,2} 0050 0051 # There are also binaries 0052 <<1,2,3>> # binary 0053 0054 # Strings and char lists 0055 "hello" # string 0056 'hello' # char list 0057 0058 # Multi-line strings 0059 """ 0060 I'm a multi-line 0061 string. 0062 """ 0063 #=> "I'm a multi-line\nstring.\n" 0064 0065 # Strings are all encoded in UTF-8: 0066 "héllò" #=> "héllò" 0067 0068 # Strings are really just binaries, and char lists are just lists. 0069 <<?a, ?b, ?c>> #=> "abc" 0070 <beginfold id='3'>[</beginfold id='3'>?a, ?b, ?c<endfold id='3'>]</endfold id='3'> #=> 'abc' 0071 0072 # `?a` in elixir returns the ASCII integer for the letter `a` 0073 ?a #=> 97 0074 0075 # To concatenate lists use `++`, for binaries use `<>` 0076 <beginfold id='3'>[</beginfold id='3'>1,2,3<endfold id='3'>]</endfold id='3'> ++ <beginfold id='3'>[</beginfold id='3'>4,5<endfold id='3'>]</endfold id='3'> #=> [1,2,3,4,5] 0077 'hello ' ++ 'world' #=> 'hello world' 0078 0079 <<1,2,3>> <> <<4,5>> #=> <<1,2,3,4,5>> 0080 "hello " <> "world" #=> "hello world" 0081 0082 # Ranges are represented as `start..end` (both inclusive) 0083 1..10 #=> 1..10 0084 lower..upper = 1..10 # Can use pattern matching on ranges as well 0085 <beginfold id='3'>[</beginfold id='3'>lower, upper<endfold id='3'>]</endfold id='3'> #=> [1, 10] 0086 0087 ## --------------------------- 0088 ## -- Operators 0089 ## --------------------------- 0090 0091 # Some math 0092 1 + 1 #=> 2 0093 10 - 5 #=> 5 0094 5 * 2 #=> 10 0095 10 / 2 #=> 5.0 0096 0097 # In elixir the operator `/` always returns a float. 0098 0099 # To do integer division use `div` 0100 div<beginfold id='2'>(</beginfold id='2'>10, 2<endfold id='2'>)</endfold id='2'> #=> 5 0101 0102 # To get the division remainder use `rem` 0103 rem<beginfold id='2'>(</beginfold id='2'>10, 3<endfold id='2'>)</endfold id='2'> #=> 1 0104 0105 # There are also boolean operators: `or`, `and` and `not`. 0106 # These operators expect a boolean as their first argument. 0107 true and true #=> true 0108 false or true #=> true 0109 # 1 and true #=> ** (ArgumentError) argument error 0110 0111 # Elixir also provides `||`, `&&` and `!` which accept arguments of any type. 0112 # All values except `false` and `nil` will evaluate to true. 0113 1 || true #=> 1 0114 false && 1 #=> false 0115 nil && 20 #=> nil 0116 !true #=> false 0117 0118 # For comparisons we have: `==`, `!=`, `===`, `!==`, `<=`, `>=`, `<` and `>` 0119 1 == 1 #=> true 0120 1 != 1 #=> false 0121 1 < 2 #=> true 0122 0123 # `===` and `!==` are more strict when comparing integers and floats: 0124 1 == 1.0 #=> true 0125 1 === 1.0 #=> false 0126 0127 # We can also compare two different data types: 0128 1 < :hello #=> true 0129 0130 # The overall sorting order is defined below: 0131 # number < atom < reference < functions < port < pid < tuple < list < bit string 0132 0133 # To quote Joe Armstrong on this: "The actual order is not important, 0134 # but that a total ordering is well defined is important." 0135 0136 ## --------------------------- 0137 ## -- Control Flow 0138 ## --------------------------- 0139 0140 # `if` expression 0141 if false <beginfold id='4'>do</beginfold id='4'> 0142 "This will never be seen" 0143 else 0144 "This will" 0145 <endfold id='4'>end</endfold id='4'> 0146 0147 # There's also `unless` 0148 unless true <beginfold id='4'>do</beginfold id='4'> 0149 "This will never be seen" 0150 else 0151 "This will" 0152 <endfold id='4'>end</endfold id='4'> 0153 0154 # Remember pattern matching? Many control-flow structures in elixir rely on it. 0155 0156 # `case` allows us to compare a value against many patterns: 0157 case <beginfold id='1'>{</beginfold id='1'>:one, :two<endfold id='1'>}</endfold id='1'> <beginfold id='4'>do</beginfold id='4'> 0158 <beginfold id='1'>{</beginfold id='1'>:four, :five<endfold id='1'>}</endfold id='1'> -> 0159 "This won't match" 0160 <beginfold id='1'>{</beginfold id='1'>:one, x<endfold id='1'>}</endfold id='1'> -> 0161 "This will match and bind `x` to `:two`" 0162 _ -> 0163 "This will match any value" 0164 <endfold id='4'>end</endfold id='4'> 0165 0166 # It's common to bind the value to `_` if we don't need it. 0167 # For example, if only the head of a list matters to us: 0168 <beginfold id='3'>[</beginfold id='3'>head | _<endfold id='3'>]</endfold id='3'> = <beginfold id='3'>[</beginfold id='3'>1,2,3<endfold id='3'>]</endfold id='3'> 0169 head #=> 1 0170 0171 # For better readability we can do the following: 0172 <beginfold id='3'>[</beginfold id='3'>head | _tail<endfold id='3'>]</endfold id='3'> = <beginfold id='3'>[</beginfold id='3'>:a, :b, :c<endfold id='3'>]</endfold id='3'> 0173 head #=> :a 0174 0175 # `cond` lets us check for many conditions at the same time. 0176 # Use `cond` instead of nesting many `if` expressions. 0177 cond <beginfold id='4'>do</beginfold id='4'> 0178 1 + 1 == 3 -> 0179 "I will never be seen" 0180 2 * 5 == 12 -> 0181 "Me neither" 0182 1 + 2 == 3 -> 0183 "But I will" 0184 <endfold id='4'>end</endfold id='4'> 0185 0186 # It is common to set the last condition equal to `true`, which will always match. 0187 cond <beginfold id='4'>do</beginfold id='4'> 0188 1 + 1 == 3 -> 0189 "I will never be seen" 0190 2 * 5 == 12 -> 0191 "Me neither" 0192 true -> 0193 "But I will (this is essentially an else)" 0194 <endfold id='4'>end</endfold id='4'> 0195 0196 # `try/catch` is used to catch values that are thrown, it also supports an 0197 # `after` clause that is invoked whether or not a value is caught. 0198 try <beginfold id='4'>do</beginfold id='4'> 0199 throw<beginfold id='2'>(</beginfold id='2'>:hello<endfold id='2'>)</endfold id='2'> 0200 catch 0201 message -> "Got #{message}." 0202 after 0203 IO.puts<beginfold id='2'>(</beginfold id='2'>"I'm the after clause."<endfold id='2'>)</endfold id='2'> 0204 <endfold id='4'>end</endfold id='4'> 0205 #=> I'm the after clause 0206 # "Got :hello" 0207 0208 ## --------------------------- 0209 ## -- Modules and Functions 0210 ## --------------------------- 0211 0212 # Anonymous functions (notice the dot) 0213 square = <beginfold id='4'>fn</beginfold id='4'><beginfold id='2'>(</beginfold id='2'>x<endfold id='2'>)</endfold id='2'> -> x * x <endfold id='4'>end</endfold id='4'> 0214 square.<beginfold id='2'>(</beginfold id='2'>5<endfold id='2'>)</endfold id='2'> #=> 25 0215 0216 # They also accept many clauses and guards. 0217 # Guards let you fine tune pattern matching, 0218 # they are indicated by the `when` keyword: 0219 f = <beginfold id='4'>fn</beginfold id='4'> 0220 x, y when x > 0 -> x + y 0221 x, y -> x * y 0222 <endfold id='4'>end</endfold id='4'> 0223 0224 f.<beginfold id='2'>(</beginfold id='2'>1, 3<endfold id='2'>)</endfold id='2'> #=> 4 0225 f.<beginfold id='2'>(</beginfold id='2'>-1, 3<endfold id='2'>)</endfold id='2'> #=> -3 0226 0227 # Elixir also provides many built-in functions. 0228 # These are available in the current scope. 0229 is_number<beginfold id='2'>(</beginfold id='2'>10<endfold id='2'>)</endfold id='2'> #=> true 0230 is_list<beginfold id='2'>(</beginfold id='2'>"hello"<endfold id='2'>)</endfold id='2'> #=> false 0231 elem<beginfold id='2'>(</beginfold id='2'><beginfold id='1'>{</beginfold id='1'>1,2,3<endfold id='1'>}</endfold id='1'>, 0<endfold id='2'>)</endfold id='2'> #=> 1 0232 0233 # You can group several functions into a module. Inside a module use `def` 0234 # to define your functions. 0235 defmodule Math <beginfold id='4'>do</beginfold id='4'> 0236 def sum<beginfold id='2'>(</beginfold id='2'>a, b<endfold id='2'>)</endfold id='2'> <beginfold id='4'>do</beginfold id='4'> 0237 a + b 0238 <endfold id='4'>end</endfold id='4'> 0239 0240 def square<beginfold id='2'>(</beginfold id='2'>x<endfold id='2'>)</endfold id='2'> <beginfold id='4'>do</beginfold id='4'> 0241 x * x 0242 <endfold id='4'>end</endfold id='4'> 0243 <endfold id='4'>end</endfold id='4'> 0244 0245 Math.sum<beginfold id='2'>(</beginfold id='2'>1, 2<endfold id='2'>)</endfold id='2'> #=> 3 0246 Math.square<beginfold id='2'>(</beginfold id='2'>3<endfold id='2'>)</endfold id='2'> #=> 9 0247 0248 # To compile our simple Math module save it as `math.ex` and use `elixirc` 0249 # in your terminal: elixirc math.ex 0250 0251 # Inside a module we can define functions with `def` and private functions with `defp`. 0252 # A function defined with `def` is available to be invoked from other modules, 0253 # a private function can only be invoked locally. 0254 defmodule PrivateMath <beginfold id='4'>do</beginfold id='4'> 0255 def sum<beginfold id='2'>(</beginfold id='2'>a, b<endfold id='2'>)</endfold id='2'> <beginfold id='4'>do</beginfold id='4'> 0256 do_sum<beginfold id='2'>(</beginfold id='2'>a, b<endfold id='2'>)</endfold id='2'> 0257 <endfold id='4'>end</endfold id='4'> 0258 0259 defp do_sum<beginfold id='2'>(</beginfold id='2'>a, b<endfold id='2'>)</endfold id='2'> <beginfold id='4'>do</beginfold id='4'> 0260 a + b 0261 <endfold id='4'>end</endfold id='4'> 0262 <endfold id='4'>end</endfold id='4'> 0263 0264 PrivateMath.sum<beginfold id='2'>(</beginfold id='2'>1, 2<endfold id='2'>)</endfold id='2'> #=> 3 0265 # PrivateMath.do_sum(1, 2) #=> ** (UndefinedFunctionError) 0266 0267 # Function declarations also support guards and multiple clauses: 0268 defmodule Geometry <beginfold id='4'>do</beginfold id='4'> 0269 def area<beginfold id='2'>(</beginfold id='2'><beginfold id='1'>{</beginfold id='1'>:rectangle, w, h<endfold id='1'>}</endfold id='1'><endfold id='2'>)</endfold id='2'> <beginfold id='4'>do</beginfold id='4'> 0270 w * h 0271 <endfold id='4'>end</endfold id='4'> 0272 0273 def area<beginfold id='2'>(</beginfold id='2'><beginfold id='1'>{</beginfold id='1'>:circle, r<endfold id='1'>}</endfold id='1'><endfold id='2'>)</endfold id='2'> when is_number<beginfold id='2'>(</beginfold id='2'>r<endfold id='2'>)</endfold id='2'> <beginfold id='4'>do</beginfold id='4'> 0274 3.14 * r * r 0275 <endfold id='4'>end</endfold id='4'> 0276 <endfold id='4'>end</endfold id='4'> 0277 0278 Geometry.area<beginfold id='2'>(</beginfold id='2'><beginfold id='1'>{</beginfold id='1'>:rectangle, 2, 3<endfold id='1'>}</endfold id='1'><endfold id='2'>)</endfold id='2'> #=> 6 0279 Geometry.area<beginfold id='2'>(</beginfold id='2'><beginfold id='1'>{</beginfold id='1'>:circle, 3<endfold id='1'>}</endfold id='1'><endfold id='2'>)</endfold id='2'> #=> 28.25999999999999801048 0280 # Geometry.area({:circle, "not_a_number"}) 0281 #=> ** (FunctionClauseError) no function clause matching in Geometry.area/1 0282 0283 # Due to immutability, recursion is a big part of elixir 0284 defmodule Recursion <beginfold id='4'>do</beginfold id='4'> 0285 def sum_list<beginfold id='2'>(</beginfold id='2'><beginfold id='3'>[</beginfold id='3'>head | tail<endfold id='3'>]</endfold id='3'>, acc<endfold id='2'>)</endfold id='2'> <beginfold id='4'>do</beginfold id='4'> 0286 sum_list<beginfold id='2'>(</beginfold id='2'>tail, acc + head<endfold id='2'>)</endfold id='2'> 0287 <endfold id='4'>end</endfold id='4'> 0288 0289 def sum_list<beginfold id='2'>(</beginfold id='2'><beginfold id='3'>[</beginfold id='3'><endfold id='3'>]</endfold id='3'>, acc<endfold id='2'>)</endfold id='2'> <beginfold id='4'>do</beginfold id='4'> 0290 acc 0291 <endfold id='4'>end</endfold id='4'> 0292 <endfold id='4'>end</endfold id='4'> 0293 0294 Recursion.sum_list<beginfold id='2'>(</beginfold id='2'><beginfold id='3'>[</beginfold id='3'>1,2,3<endfold id='3'>]</endfold id='3'>, 0<endfold id='2'>)</endfold id='2'> #=> 6 0295 0296 # Elixir modules support attributes, there are built-in attributes and you 0297 # may also add custom ones. 0298 defmodule MyMod <beginfold id='4'>do</beginfold id='4'> 0299 @moduledoc """ 0300 This is a built-in attribute on a example module. 0301 """ 0302 0303 @my_data 100 # This is a custom attribute. 0304 IO.inspect<beginfold id='2'>(</beginfold id='2'>@my_data<endfold id='2'>)</endfold id='2'> #=> 100 0305 <endfold id='4'>end</endfold id='4'> 0306 0307 ## --------------------------- 0308 ## -- Structs and Exceptions 0309 ## --------------------------- 0310 0311 # Structs are extensions on top of maps that bring default values, 0312 # compile-time guarantees and polymorphism into Elixir. 0313 defmodule Person <beginfold id='4'>do</beginfold id='4'> 0314 defstruct name: nil, age: 0, height: 0 0315 <endfold id='4'>end</endfold id='4'> 0316 0317 joe_info = %Person<beginfold id='1'>{</beginfold id='1'> name: "Joe", age: 30, height: 180 <endfold id='1'>}</endfold id='1'> 0318 #=> %Person{age: 30, height: 180, name: "Joe"} 0319 0320 # Access the value of name 0321 joe_info.name #=> "Joe" 0322 0323 # Update the value of age 0324 older_joe_info = %<beginfold id='1'>{</beginfold id='1'> joe_info | age: 31 <endfold id='1'>}</endfold id='1'> 0325 #=> %Person{age: 31, height: 180, name: "Joe"} 0326 0327 # The `try` block with the `rescue` keyword is used to handle exceptions 0328 try <beginfold id='4'>do</beginfold id='4'> 0329 raise "some error" 0330 rescue 0331 RuntimeError -> "rescued a runtime error" 0332 _error -> "this will rescue any error" 0333 <endfold id='4'>end</endfold id='4'> 0334 #=> "rescued a runtime error" 0335 0336 # All exceptions have a message 0337 try <beginfold id='4'>do</beginfold id='4'> 0338 raise "some error" 0339 rescue 0340 x in <beginfold id='3'>[</beginfold id='3'>RuntimeError<endfold id='3'>]</endfold id='3'> -> 0341 x.message 0342 <endfold id='4'>end</endfold id='4'> 0343 #=> "some error" 0344 0345 ## --------------------------- 0346 ## -- Concurrency 0347 ## --------------------------- 0348 0349 # Elixir relies on the actor model for concurrency. All we need to write 0350 # concurrent programs in elixir are three primitives: spawning processes, 0351 # sending messages and receiving messages. 0352 0353 # To start a new process we use the `spawn` function, which takes a function 0354 # as argument. 0355 f = <beginfold id='4'>fn</beginfold id='4'> -> 2 * 2 <endfold id='4'>end</endfold id='4'> #=> #Function<erl_eval.20.80484245> 0356 spawn<beginfold id='2'>(</beginfold id='2'>f<endfold id='2'>)</endfold id='2'> #=> #PID<0.40.0> 0357 0358 # `spawn` returns a pid (process identifier), you can use this pid to send 0359 # messages to the process. To do message passing we use the `send` operator. 0360 # For all of this to be useful we need to be able to receive messages. This is 0361 # achieved with the `receive` mechanism: 0362 0363 # The `receive do` block is used to listen for messages and process 0364 # them when they are received. A `receive do` block will only 0365 # process one received message. In order to process multiple 0366 # messages, a function with a `receive do` block must recursively 0367 # call itself to get into the `receive do` block again. 0368 0369 defmodule Geometry <beginfold id='4'>do</beginfold id='4'> 0370 def area_loop <beginfold id='4'>do</beginfold id='4'> 0371 receive <beginfold id='4'>do</beginfold id='4'> 0372 <beginfold id='1'>{</beginfold id='1'>:rectangle, w, h<endfold id='1'>}</endfold id='1'> -> 0373 IO.puts<beginfold id='2'>(</beginfold id='2'>"Area = #{w * h}"<endfold id='2'>)</endfold id='2'> 0374 area_loop<beginfold id='2'>(</beginfold id='2'><endfold id='2'>)</endfold id='2'> 0375 <beginfold id='1'>{</beginfold id='1'>:circle, r<endfold id='1'>}</endfold id='1'> -> 0376 IO.puts<beginfold id='2'>(</beginfold id='2'>"Area = #{3.14 * r * r}"<endfold id='2'>)</endfold id='2'> 0377 area_loop<beginfold id='2'>(</beginfold id='2'><endfold id='2'>)</endfold id='2'> 0378 <endfold id='4'>end</endfold id='4'> 0379 <endfold id='4'>end</endfold id='4'> 0380 <endfold id='4'>end</endfold id='4'> 0381 0382 # Compile the module and create a process that evaluates `area_loop` in the shell 0383 pid = spawn<beginfold id='2'>(</beginfold id='2'><beginfold id='4'>fn</beginfold id='4'> -> Geometry.area_loop<beginfold id='2'>(</beginfold id='2'><endfold id='2'>)</endfold id='2'> <endfold id='4'>end</endfold id='4'><endfold id='2'>)</endfold id='2'> #=> #PID<0.40.0> 0384 # Alternatively 0385 pid = spawn<beginfold id='2'>(</beginfold id='2'>Geometry, :area_loop, <beginfold id='3'>[</beginfold id='3'><endfold id='3'>]</endfold id='3'><endfold id='2'>)</endfold id='2'> 0386 0387 # Send a message to `pid` that will match a pattern in the receive statement 0388 send pid, <beginfold id='1'>{</beginfold id='1'>:rectangle, 2, 3<endfold id='1'>}</endfold id='1'> 0389 #=> Area = 6 0390 # {:rectangle,2,3} 0391 0392 send pid, <beginfold id='1'>{</beginfold id='1'>:circle, 2<endfold id='1'>}</endfold id='1'> 0393 #=> Area = 12.56000000000000049738 0394 # {:circle,2} 0395 0396 # The shell is also a process, you can use `self` to get the current pid 0397 self<beginfold id='2'>(</beginfold id='2'><endfold id='2'>)</endfold id='2'> #=> #PID<0.27.0> 0398 0399 # Code not found in the original, but needed to test the full range of the syntax 0400 0401 def function, do: <beginfold id='1'>{</beginfold id='1'>:ok, result<endfold id='1'>}</endfold id='1'> 0402 0403 <beginfold id='3'>[</beginfold id='3'> 0404 :a, 0405 :b, 0406 :c 0407 <endfold id='3'>]</endfold id='3'> 0408 0409 %<beginfold id='1'>{</beginfold id='1'> 0410 a: "a", 0411 b: "b", 0412 c: "c" 0413 <endfold id='1'>}</endfold id='1'> 0414 0415 %A<beginfold id='1'>{</beginfold id='1'> 0416 a: "a", 0417 b: "b", 0418 c: "c" 0419 <endfold id='1'>}</endfold id='1'>