Giter VIP home page Giter VIP logo

learn-elixir's Introduction

Learn elixir logo


Why?

Key Advantages

  • Scalability
  • Speed
  • Compiled and run on the Erlang VM ("BEAM"). (Renowned for efficiency)
  • Much better "garbage collection" than virtually any other VM
  • Many tiny processes (as opposed to "threads" which are more difficult to manage)
  • Functional language with dynamic typing
  • Immutable data so "state" is always predictable!
    image
  • High reliability, availability and fault tolerance (because of Erlang) means apps built with Elixir are run in production for years without any "downtime"!
  • Real-time web apps are "easy" (or at least easier than many other languages!) as WebSockets & streaming are baked-in

Things will go wrong with code, and Elixir provides supervisors which describe how to restart parts of your system when things don't go as planned.

What?

"Elixir is a dynamic, functional language designed for building scalable and maintainable applications."

Video Introductions

If you have the time, these videos give a nice contextual introduction into what Elixir is, what it's used for and how it works:

Not a video learner? Looking for a specific learning? https://elixirschool.com/ is an excellent, free, open-source resource that explains all things Elixir πŸ“– ❀️.

How?

Before you learn Elixir as a language you will need to have it installed on your machine.

To do so you can go to http://elixir-lang.org/install.html or follow our guide here:

Installation:

Mac:

Using the Homebrew package manager: brew install elixir

If you have any trouble with ssl when running an Elixir App on your Mac, see: /install-mac.md

Ubuntu:

  • Add the Erlang Solutions repo:
wget https://packages.erlang-solutions.com/erlang-solutions_2.0_all.deb && sudo dpkg -i erlang-solutions_2.0_all.deb
  • Run: sudo apt-get update
  • Install the Erlang/OTP platform and all of its applications: sudo apt-get install esl-erlang
  • Install Elixir: sudo apt-get install elixir

Windows:

choco install elixir

Livebook:

  • Easy peasy if you have Elixir installed. Just click below

πŸ‘‰ Screenshot 2023-01-13 at 10 15 23

Once Livebook installed on your machine, just click on the button below (or fork and run it):

Run in Livebook

  • Alternatively, you can run a Docker image, no need to install Elixir or Livebook. Launch Docker and run the Livebook image:
docker run -p 8080:8080 -p 8081:8081 --pull always -e LIVEBOOK_PASSWORD="securesecret" livebook/livebook

and in another terminal you launch the browser (you will need to authneticate with "securesecret") with the command:

open http://localhost:8080/import?url=https://github.com/dwyl/learn-elixir/blob/main/learn-elixir-on-livebook.livemd
  • Finally, if you don't have Docker nor Elixir and Livebook installed, you can run a remote version in the cloud. Follow this!

You (right-)click on the grey button "Run in Livebook" below.

❗ You right-click" to keep this reminder page open πŸ˜‰ because you will need to remember to do 2 things:

  1. firstly, look at the bottom for the link "see source" as showed below, πŸ€”, and click.

Screenshot 2023-01-13 at 10 23 14

  1. and finally, select the file [dwyl-learn-elixir.livemd]. It should be printed in green, and "join session". πŸ€—

Happy learning! πŸ₯³

This links to the remote Livebook: πŸ‘‰ Run in Livebook

Learn Elixir

Commands

  • After installing Elixir you can open the interactive shell by typing iex. This allows you to type in any Elixir expression and see the result in the terminal.

  • Type in h followed by the function name at any time to see documentation information about any given built-in function and how to use it. E.g If you type h round into the (iex) terminal you should see something like this:

elixir-h

  • Typing i followed by the value name will give you information about a value in your code:

elixir-i

Basic Types

This section brings together the key information from Elixir's Getting Started documentation and multiple other sources. It will take you through some examples to practice using and familiarise yourself with Elixir's 7 basic types.

Elixir's 7 basic types:

  • integers
  • floats
  • booleans
  • atoms
  • strings
  • lists
  • tuples

Numbers

Type 1 + 2 into the terminal (after opening iex):

iex> 1 + 2
3

More examples:

iex> 5 * 5
25
iex> 10 / 2
5.0

# When using the `/` with two integers this gives a `float` (5.0).
# If you want to do integer division or get the division remainder
# you can use the `div` or `rem` functions
iex> div(10, 2)
5
iex> div 10, 2
5
iex> rem 10, 3
1

Booleans

Elixir supports true and false as booleans.

iex> true
true
iex> false
false

iex> is_boolean(true)
true
iex> is_boolean(1)
false

Truthiness: truthy and falsy values

Besides the booleans true and false Elixir also has the concept of a "truthy" or "falsy" value.

  • a value is truthy when it is neither false nor nil
  • a value is falsy when it is false or nil

Elixir has functions, like and/2, that only work with booleans, but also functions that work with these truthy/falsy values, like &&/2 and !/1.

The syntax <function_name>/<number> is the convention used in Elixir to identify a function named <function_name> that takes <number> parameters. The value <number> is also referred to as the function arity. In Elixir each function is identified univocally both by its name and its arity. More information can be found here. We can check the truthiness of a value by using the !/1 function twice.

Truthy values:

iex> !!true
true
iex> !!5
true
iex> !![1,2]
true
iex> !!"foo"
true

Falsy values (of which there are exactly two):

iex> !!false
false
iex> !!nil
false

Atoms

Atoms are constants where their name is their own value (some other languages call these Symbols).

iex> :hello
:hello
iex> :hello == :world
false

true and false are actually atoms in Elixir

Names of modules in Elixir are also atoms. MyApp.MyModule is a valid atom, even if no such module has been declared yet.

iex> is_atom(MyApp.MyModule)
true

Atoms are also used to reference modules from Erlang libraries, including built-in ones.

iex> :crypto.strong_rand_bytes 3
<<23, 104, 108>>

One popular use of atoms in Elixir is to use them as messages for pattern matching. Let's say you have a function which processes an http request. The outcome of this process is either going to be a success or an error. You could therefore use atoms to indicate whether or not this process is successful.

def process(file) do
  lines = file |> split_lines

  case lines do
    nil ->
      {:error, "failed to process file"}
    lines ->
      {:ok, lines}
  end
end

Here we are saying that the method, process/1 will return a tuple response. If the result of our process is successful, it will return {:ok, lines}, however if it fails (e.g. returns nil) then it will return an error. This will allows us to pattern match on this result.

{:ok, lines} = process('text.txt')

Thus, we can be sure that we will always have the lines returned to us and never a nil value (because it will throw an error). This becomes extremely useful when piping multiple methods together.

Strings

Strings are surrounded by double quotes.

iex> "Hello World"
"Hello world"

# You can print a string using the `IO` module
iex> IO.puts "Hello world"
"Hello world"
:ok

Lists

Elixir uses square brackets to make a list.

iex> myList = [1,2,3]
iex> myList
[1,2,3]

iex> length(myList)
3

# concatenating lists together
iex> [1, 2, 3] ++ [4, 5, 6]
[1, 2, 3, 4, 5, 6]

# removing items from a list
iex> [1, true, 2, false, 3, true] -- [true, false]
[1, 2, 3, true]

Lists are enumerable and can use the Enum module to perform iterative functions such as mapping.

Tuples

Elixir uses curly brackets to make a tuple.

Tuples are similar to lists but are not suited to data sets that need to be updated or added to regularly.

iex> tuple = {:ok, "hello"}
{:ok, "hello"}

# get element at index 1
iex> elem(tuple, 1)
"hello"

# get the size of the tuple
iex> tuple_size(tuple)
2

Tuples are not enumerable and there are far fewer functions available in the Tuple module. You can reference tuple values by index but you cannot iterate over them. If you must treat your tuple as a list, then convert it using Tuple.to_list(your_tuple)

Lists or Tuples?

If you need to iterate over the values use a list.

When dealing with large lists or tuples:

  • Updating a list (adding or removing elements) is fast

  • Updating a tuple is slow

  • Reading a list (getting its length or selecting an element) is slow

  • Reading a tuple is fast

source: http://stackoverflow.com/questions/31192923/lists-vs-tuples-what-to-use-and-when

Functions and Modules

Anonymous functions

Anonymous functions start with fn and end with end.

iex> add = fn a, b -> a + b end

iex> add.(1, 2)
3

Note a dot . between the variable add and parenthesis is required to invoke an anonymous function.

In Elixir, functions are first class citizens meaning that they can be passed as arguments to other functions the same way integers and strings can.

iex> is_function(add)
true

This uses the inbuilt function is_function which checks to see if the parameter passed is a function and returns a bool.

Anonymous functions are closures (named functions are not) and as such they can access variables that are in scope when the function is defined. You can define a new anonymous function that uses the add anonymous function we have previously defined:

iex> double = fn a -> add.(a, a) end

iex> double.(5)
10

These functions can be useful but will no longer be available to you. If you want to make something more permanent then you can create a module.

Modules

With modules you're able to group several functions together. Most of the time it is convenient to write modules into files so they can be compiled and reused.

Get started by creating a file named math.ex, open it in your text editor and add the following code

defmodule Math do
  def sum(a, b) do
    a + b
  end
end

In order to create your own modules in Elixir, use the defmodule macro, then use the def macro to define functions in that module. So in this case the module is Math and the function is sum.

Once this is saved the file can be compiled by typing elixirc into the terminal followed by the file name.

$ elixirc math.ex

This will generate a file named Elixir.Math.beam containing the bytecode for the defined module. If we start iex again, our module definition will be available (provided that iex is started in the same directory the bytecode file is in):

iex> Math.sum(1, 2)
3

Create Your First Elixir Project

To get started with your first Elixir project you need to make use of the Mix build tool that comes with Elixir. Mix allows you to do a number of things including:

  • Create projects
  • Compile projects
  • Run tasks
    • Testing
    • Generate documentation
  • Manage dependencies

To generate a new project follow these steps:

Initialise

Initialise a project by typing the following command in your terminal, replacing [project_name] with the name of your project:

mix new [project_name]

e.g:

mix new animals

We have chosen to call our project 'animals'

This will create a new folder with the given name of your project and should also print something that looks like this to the command line:

* creating README.md
* creating .formatter.exs
* creating .gitignore
* creating mix.exs
* creating lib
* creating lib/animals.ex
* creating test
* creating test/test_helper.exs
* creating test/animals_test.exs

Your Mix project was created successfully.
You can use "mix" to compile it, test it, and more:

    cd animals
    mix test

Run "mix help" for more commands.

Navigate to your newly created directory:

> cd animals

Open the directory in your text editor. You will be able to see that Elixir has generated a few files for us that are specific to our project:

  • lib/animals.ex
  • test/animals_test.ex

Edit animals.ex

Open up the animals.ex file in the lib directory. You should already see some hello-world boilerplate like this:

defmodule Animals do
  @moduledoc """
  Documentation for Animals.
  """

  @doc """
  Hello world.

  ## Examples

      iex> Animals.hello()
      :world

  """
  def hello do
    :world
  end
end

Elixir has created a module with the name of your project along with a function that prints out a :world atom when called. It's also added boilerplate for module and function documentation - the first part of the file. (we will go into more detail about documentation later)

Run the Code

Let's test out the boilerplate code. In your project directory type the following command:

> iex -S mix

What this means is: "Start the Elixir REPL and compile with the context of my current project". This allows you to access modules and functions created within the file tree.
Call the hello-world function given to us by Elixir. It should print out the :world atom to the command line:

> Animals.hello
# :world

Define Functions

Let's start to create our own methods in the Animals module. Replace the hello-world function with the following:

@doc """
create_zoo returns a list of zoo animals

## Examples

    iex> Animals.create_zoo
    ["lion", "tiger", "gorilla", "elephant", "monkey", "giraffe"]

"""
def create_zoo do
  ["lion", "tiger", "gorilla", "elephant", "monkey", "giraffe"]
end

To run our new code we will first have to recompile our iex. This can be done by typing:

> recompile()

Now we will have access to the create_zoo method. Try it out in the command line:

> Animals.create_zoo
# ["lion", "tiger", "gorilla", "elephant", "monkey", "giraffe"]

Extend Functions

Let's extend the Animals module. Imaging you're visiting the zoo but you can't decide which order to view the animals. We can create a randomise function before the final end that takes a list of animals and returns a new list with a random order:

@doc """
randomise takes a list of zoo animals and returns a new randomised list with
the same elements as the first.

## Examples

    iex> zoo = Animals.create_zoo
    iex> Animals.randomise(zoo)
    ["monkey", "tiger", "elephant", "gorilla", "giraffe", "lion"]

"""
def randomise(zoo) do
  Enum.shuffle(zoo)
end

Note: we are making use of a pre-built module called Enum which has a list of functions that you can use on enumerables such as lists. Documentation available at: hexdocs.pm/elixir/Enum.html

Add More Functions!

Let's add another function to the Animals module. We want to find out if our zoo contains an animal:

@doc """
contains? takes a list of zoo animals and a single animal and returns a boolean
as to whether or not the list contains the given animal.

## Examples

    iex> zoo = Animals.create_zoo
    iex> Animals.contains?(zoo, "gorilla")
    true
"""
def contains?(zoo, animal) do
  Enum.member?(zoo, animal)
end

NOTE: It's convention when writing a function that returns a boolean to add a question mark after the name of the method.

Pattern Matching Example

Create a function that takes a list of animals and the number of animals that you'd like to see and returns a list of animals:

@doc """
see_animals takes a list of zoo animals and the number of animals that
you want to see and then returns a list

## Examples

    iex> zoo = Animals.create_zoo
    iex> Animals.see_animals(zoo, 2)
    ["monkey", "giraffe"]
"""
def see_animals(zoo, count) do
  # Enum.split returns a tuple so we have to pattern match on the result
  # to get the value we want out
  {_seen, to_see} = Enum.split(zoo, -count)
  to_see
end

Save Data to File

Write a function that will save our list of animals to a file:

@doc """
save takes a list of zoo animals and a filename and saves the list to that file

## Examples

    iex> zoo = Animals.create_zoo
    iex> Animals.save(zoo, "my_animals")
    :ok
"""
def save(zoo, filename) do
  # erlang is converting the zoo list to something that can be written to the
  # file system
  binary = :erlang.term_to_binary(zoo)
  File.write(filename, binary)
end

In your command line, run the following after recompiling:

> zoo = Animals.create_zoo
> Animals.save(zoo, "my_animals")

This will create a new file in your file tree with the name of the file that you specified in the function. It will contain some odd characters:

οΏ½l\οΏ½οΏ½οΏ½οΏ½mοΏ½οΏ½οΏ½οΏ½lionmοΏ½οΏ½οΏ½οΏ½tigermοΏ½οΏ½οΏ½οΏ½gorillamοΏ½οΏ½οΏ½οΏ½elephantmοΏ½οΏ½οΏ½οΏ½monkeymοΏ½οΏ½οΏ½οΏ½giraffej

Retrieve Data from File

Write a function that will fetch data from the file:

@doc """
load takes filename and returns a list of animals if the file exists

## Examples

    iex> Animals.load("my_animals")
    ["lion", "tiger", "gorilla", "elephant", "monkey", "giraffe"]
    iex> Animals.load("aglkjhdfg")
    "File does not exist"

"""
def load(filename) do
  # here we are running a case expression on the result of File.read(filename)
  # if we receive an :ok then we want to return the list
  # if we receive an error then we want to give the user an error-friendly message
  case File.read(filename) do
    {:ok, binary} -> :erlang.binary_to_term(binary)
    {:error, _reason} -> "File does not exist"
  end
end

The case expression allows us to pattern match against various options and react accordingly.

Pipe Operator

What if we wanted to call some of our functions in succession to another? Let's create a function that creates a zoo, randomises it and then returns a selected number of animals to go and see:

@doc """
selection takes a number, creates a zoo, randomises it and then returns a list
of animals of length selected

## Examples

    iex> Animals.selection(2)
    ["gorilla", "giraffe"]

"""
def selection(number_of_animals) do
  # We are using the pipe operator here. It takes the value returned from
  # the expression and passes it down as the first argument in the expression
  # below. see_animals takes two arguments but only one needs to be specified
  # as the first is provided by the pipe operator
  Animals.create_zoo()
  |> Animals.randomise()
  |> Animals.see_animals(number_of_animals)
end

Now that we have the functionality for our module, let's take a look at the documentation that we have written and how we can maximise its use.

Documentation

When we created a new project with mix, it created a file for us called mix.exs which is referred to as the 'MixFile'. This file holds information about our project and its dependencies.

At the bottom of the file it gives us a function called deps which manages all of the dependencies in our project. To install a third party package we need to manually write it in the deps function (accepts a tuple of the package name and the version) and then install it in the command line. Let's install ex_doc as an example:

Add the following to the deps function in your mix.exs file:

defp deps do
  [
    {:ex_doc, "~> 0.21"}
  ]
end

Then in the command line quit your iex shell and enter the following to install the ex_docs dependency:

> mix deps.get

You might receive an error saying:

Could not find Hex, which is needed to build dependency :ex_doc
Shall I install Hex? (if running non-interactively,
use: "mix local.hex --force") [Yn]

If you do then just enter y and then press enter. This will install the dependencies that you need.

Once ex_docs has been installed, run the following command to generate documentation (make sure you're not in iex):

> mix docs

This will generate documentation that can be viewed if you copy the file path of the index.html file within the newly created doc folder and then paste it in your browser. If you have added documentation to your module and functions as per the examples above, you should see something like the following:

api

It looks exactly like the format of the official Elixir docs because they used the same tool to create theirs. Here is what the method documentation should look like if you click on Animals:

doc

functions

This is an incredibly powerful tool that comes 'baked in' with elixir. It means that other developers who are joining the project can be brought up to speed incredibly quickly!

Testing

When you generate a project with Elixir it automatically gives you a number of files and directories. One of these directories is called test and it holds two files that should have names like:

  • [project_name]_test.exs
  • test_helper.exs

Our first file was called animals_test.exs and it contained some boilerplate that looks like:

defmodule AnimalsTest do
  use ExUnit.Case
  doctest Animals

  test "greets the world" do
    assert Animals.hello() == :world
  end
end

NOTE: It automatically includes a line called doctest Animals. What this means is that it can run tests from the examples in the documentation that you write for your functions

To run the tests enter the following in your terminal: mix test
It should print out whether the tests pass or fail.

Let's add some tests of our own. Firstly let's write a test for the Animals.randomise function. The reason why we wouldn't want to write a doctest for this is because the output value changes everytime you call it. Here's how we would write a test for that type of function:

In the animals_test.exs file, remove the boilerplate "greets the world" test and then add this to test that the order of the animals in zoo changes (is randomised):

test "randomise" do
  zoo = Animals.create_zoo
  assert zoo != Animals.randomise(zoo)
end

NOTE: You do not need to install and require any external testing frameworks. It all comes with the Elixir package. Simply write test followed by a string representing what you are trying to test and then write your assertion.

The test above isn't completely air-tight. Elixir provides you with assertions that can help deal with things like this. The test could be re-written like so:

test "randomise" do
  zoo = Animals.create_zoo
  refute zoo == Animals.randomise(zoo)
end

This is basically saying "prove to be false that zoo is equal to Animals.randomise(zoo)"

If you want to learn about code coverage then check out the following tutorial, https://github.com/dwyl/learn-elixir/tree/master/codecov_example

Formatting

In Elixir version 1.6 the mix format task was introduced. see: elixir-lang/elixir#6643

mix format is a built-in way to format your Elixir code according to the community-agreed consistent style. This means all code will look consistent across projects (personal, "work" & hex.pm packages) which makes learning faster and maintainability easier! At present, using the formatter is optional, however most Elixir projects have adopted it.

To use the mix task in your project, you can either check files individually, e.g:

mix format path/to/file.ex

Or you can define a pattern for types of files you want to check the format of:

mix format "lib/**/*.{ex,exs}"

will check all the .ex and .exs files in the lib/ directory.

Having to type this pattern each time you want to check the files is tedious. Thankfully, Elixir has you covered.

In the root of your Elixir project, you will find a .formatter.exs config file with the following code:

# Used by "mix format"
[
  inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"]
]

This means that if you run mix format it will check the mix.exs file and all .ex and .exs files in the config, lib/ and test directories.

This is the most common pattern for running mix format. Unless you have a reason to "deviate" from it, it's a good practice to keep it as it is.

Simply run:

mix format

And your code will now follow Elixir's formatting guidelines.

We recommend installing a plugin in your Text Editor to auto-format:

Publishing

To publish your Elixir package to Hex.pm:

  • Check the version in mix.exs is up to date and that it follows the semantic versioning format:

    MAJOR.MINOR.PATCH where

      MAJOR version when you make incompatible API changes
      MINOR version when you add functionality in a backwards-compatible manner
      PATCH version when you make backwards-compatible bug fixes
    
  • Check that the main properties of the project are defined in mix.exs

    • name: The name of the package
    • description: A short description of the package
    • licenses: The names of the licenses of the package
    • NB. dwyl's cid repo contains an example of a more advanced mix.exs file where you can see this in action
  • Create a Hex.pm account if you do not have one already.

  • Make sure that ex_doc is added as a dependency in you project

defp deps do
[
  {:ex_doc, "~> 0.21", only: :dev}
]
end

When publishing a package, the documentation will be automatically generated. So if the dependency ex_doc is not declared, the package won't be able to be published

  • Run mix hex.publish and if all the information are correct reply Y

If you have not logged into your Hex.pm account in your command line before running the above command, you will be met with the following...

No authenticated user found. Do you want to authenticate now? [Yn]

You will need to reply Y and follow the on-screen instructions to enter your Hex.pm username and password.

After you have been authenticated, Hex will ask you for a local password that applies only to the machine you are using for security purposes.

Create a password for this and follow the onscreen instructions to enter it.

  • Now that your package is published you can create a new git tag with the name of the version:
    • git tag -a 0.1.0 -m "0.1.0 release"
    • git push --tags

Congratulations!

That's it, you've generated, formatted and published your first Elixir project πŸŽ‰

Want More?

If you want a more detailed example of publishing a real-world package and re-using it in a real-world project, see: code-reuse-hexpm.md


Data Structures

Maps

Maps are very similar to Object literals in JavaScript. They have almost the same syntax except for a % symbol. They look like this:

animal = %{
  name: "Rex",
  type: "dog",
  legs: 4
}

Values can be accessed in a couple of ways. The first is by dot notation just like JavaScript:

name = animal.name
# Rex

The second way values can be accessed is by pattern matching. Let's say we wanted to assign values to variables for each of the key-value pairs in the map. We would write something that looks like this:

iex> %{
  name: name,
  type: type,
  legs: legs
} = animal
# we now have access to the values by typing the variable names
iex> name
# "Rex"
iex> type
# "dog"
iex> legs
# 4

Updating a value inside a map

Due to the immutability of Elixir, you cannot update a map using dot notation for example:

iex> animal = %{
  name: "Rex",
  type: "dog",
  legs: 4
}
iex> animal.name = "Max" # this cannot be done!

In Elixir we can only create new data structures as opposed to manipulating existing ones. So when we update a map, we are creating a new map with our new values. This can be done in a couple of ways:

  • Function
  • Syntax
  1. Using a function
    We can update a map using Map.put(map, key, value). This takes the map you want to update followed by the key we want to reassign and lastly the value that we want to reassign to the key:
iex> updatedAnimal = Map.put(animal, :name, "Max")
iex> updatedAnimal
# %{legs: 4, name: "Max", type: "dog"}
  1. Using syntax
    We can use a special syntax for updating a map in Elixir. It looks like this:
iex> %{animals | name: "Max"}
# %{legs: 4, name: "Max", type: "dog"}

NOTE: Unlike the function method above, this syntax can only be used to UPDATE a current key-value pair inside the map, it cannot add a new key value pair.

Processes

When looking into Elixir you may have heard about its processes and its support for concurrency. In fact we even mention processes as one of the key advantages. If you're anything like us, you're probably wondering what this actually means for you and your code. This section aims to help you understand what they are and how they can help improve your Elixir projects.

Elixir-lang describes processes as:

In Elixir, all code runs inside processes. Processes are isolated from each other, run concurrent to one another and communicate via message passing. Processes are not only the basis for concurrency in Elixir, but they also provide the means for building distributed and fault-tolerant programs.

Now that we have a definition, let's start by spawning our first process.

Spawning a process

Create a file called math.exs and insert the following code:

defmodule Math do
  def add(a, b) do
    a + b
    |> IO.inspect()
  end
end

Now head over to your terminal and enter the following, iex math.exs. This will load your Math module into your iex session. Now in iex type:

spawn(Math, :add, [1,2])

You will see something similar to:

3
#PID<0.118.0>

This is your log followed by a process identifier, PID for short. A PID is a unique id for a process. It could be unique among all processes in the world, but here it's just unique for your application.

So what just happened here. We called the spawn/3 function and passed it 3 arguments. The module name, the function name (as an atom), and a list of the arguments that we want to give to our function. This one line of code spawned a process for us πŸŽ‰ πŸ₯³

Normally we would not see the result of the function (3 in this case). The only reason we have is because of the IO.inspect in the add function. If we removed this the only log we would have is the PID itself.

This might make you wonder, what good is spawning a process if I can't get access to the data it returns. This is where messages come in.

Sending messages between processes

Let's start by exiting iex and removing the the IO.inspect line from our code. Now that that is done let's get our add function to send its result in a message.

Update your file to the following:

defmodule Math do
  def add(a, b) do
    receive do
      senders_pid ->
        send(senders_pid, a + b)
    end
  end

  def double(n) do
    spawn(Math, :add, [n,n])
    |> send(self())

    receive do
      doubled ->
        doubled
    end
  end
end

Let's go through all the new code. We have added a new function called double. This function spawns the Math.add/2 function (as we did in the iex shell in the previous example). Remember the spawn function returned a PID. We use this PID on the next line with |> send(self()). send/2 takes two arguments, a destination and a message. For us the destination is the PID created by the spawn function on the line above. The message is self/0 which returns the PID of the calling process (the PID of double).

We then call receive/1 which checks if there is a message matching the clauses in the current process. It works very similarly to a case statement. Our message is simple and just returns whatever the message was.

We have also updated our add/2 function so that it also contains a receive and a send. This receive, receives the PID of the sender. Once it has that message it calls the send function to send a message back to the sender. The message it sends is a+b.

This will trigger the receive block in our double function. As mentioned above, it simply returns the message it receives which is the answer from add.

Let's test this code in iex. Change to your terminal and type iex math.exs again. In iex type Math.double(5).

You should see

10

VERY COOL. We just spawned a process which did a task for us and returned the data.

Concurrency

Now that we can create processes that can send messages to each other, let's see if we can use them for something a little more intensive than doubling an integer.

In this example we will aim to see exactly how concurrency can be used to speed up a function (and in turn, hopefully a project).

We are going to do this by solving factorials using two different approaches. One will solve them on a single process and the other will solve them using multiple processes.

(A factorial is the product of an integer and all the integers below it; e.g. factorial(4) (4!) is equal to 1 * 2 * 3 * 4 or 24.)

Create a new file called factorial.exs with the following code:

defmodule Factorial do
  def spawn(n) do
    1..n
    |> Enum.chunk_every(4)
    |> Enum.map(fn(list) ->
      spawn(Factorial, :_spawn_function, [list])
      |> send(self())

      receive do
        n -> n
      end
    end)
    |> calc_product()
  end

  def _spawn_function(list) do
    receive do
      sender ->
        product = calc_product(list)
        send(sender, product)
    end
  end

  # used on the single process
  def calc_product(n) when is_integer(n) do
    Enum.reduce(1..n, 1, &(&1 * &2))
  end

  # used with multiple processes
  def calc_product(list) do
    Enum.reduce(list, 1, &(&1 * &2))
  end
end

The & symbol is called the capture operator, which can be used to quickly generate anonymous functions that expect at least one argument. The arguments can be accessed inside the capture operator &() with &X, where X refers to the input number of the argument.

There is no difference between

add_capture = &(&1 + &2)
add_fn = fn a, b -> a + b end

Before we go any further let's take a quick look at the calc_product function. You will see that there are 2 definitions for this function. One which takes a list and another which takes an integer and turns it into a range. Other than this, the functions work in exactly the same way. They both call reduce on an enumerable and multiply the current value with the accumulator.

(The reason both work the same way is so that we could see the effect multiple processes running concurrently have on how long it takes for us to get the results of our factorial. I didn't want differences in a functions approach to be the reason for changes in time. Also these factorial functions are not perfect and do not need to be. That is not what we are testing here.)

Now we can test if our calc_product function works as expected. In your iex shell load the Factorial module with c("factorial.exs"). Now type Factorial.calc_product(5). If you get an output of 120 then everything is working as expected and you just solved a factorial on a single process.

This works well on a smaller scale but what if we need/want to work out factorial(100_000). If we use this approach it will take quite some time before it we get the answer returned (something we will log a little later). The reason for this is because this massive sum is being run on a single process.

This is where spawning multiple processes comes in. By spawning multiple processes, instead of giving all of the work to a single process, we can share the load between any number of processes. This way each process is only handling a portion of the work and we should be able to get our solution faster.

This sounds good in theory but let's see if we can put it into practice.

First, let's look through the spawn function and try to work out what it is doing exactly.

The function starts by converting an integer into a range which it then 'chunks' into a list of lists with 4 elements. The number 4 itself is not important, it could have been 5, 10, or 1000. What is important about it, is that it influences the number of processes we will be spawning. The larger the size of the 'chunks' the fewer processes are spawned.

Next, we map over the 'chunked' range and call the spawn function. This spawns a new process for each chunked list running the _spawn_function/1. Afterwards, the process running the spawn/1 function sends the newly created process a message and waits for a response message.

The _spawn_function function is pretty simple. It uses the exact same pattern we used in our add function earlier. It receives a message with the senders PID and then sends a message back to them. The message it sends back is the result of the calc_product function.

Once each process in the map function has received a result, we then call the calc_product once more to turn the list of results from map into a single integer, the factorial. In total the spawn/1 function will end up calling calc_product for a list with n elements: n % 4 + 1 if n % 4 == 0 else n % 4 + 2 times.

Remember, we split the original list into lists of 4 elements. The only exception is the last chunk, which may contain fewer elements:

[1, 2, 3, 4, 5] -> [[1, 2, 3, 4], [5]]

For each chunked list we call calc_product and to calculate the final result, the factorial, once.

Now that we have been through the code the only things left are to run the code and to time the code.

To time the execution of our code, add the following to your factorial.exs file:

  # just a helper function used to time the other functions
  def run(f_name, args) do
    :timer.tc(Factorial, f_name, args)
    |> elem(0) # only displays the time as I didn't want to log numbers that could have thousands of digits
    |> IO.inspect(label: "----->")
  end

You can feel free to comment out the |> elem(0) line. I left it in because we are about to have a MASSIVE number log in our terminal and we don't really need to see it.

Now we have all the code we will need. All that's left is to call the code.

Let's go back to our iex shell and retype the c("factorial.exs") command. Now type the following Factorial.run(:calc_product, [10_000]). You should get a log of the number of milliseconds it took to run the function.

Next type Factorial.run(:spawn, [10_000]). Compare to two logs. You should have something that looks like this...

image.

Feel free to try this test again with even larger numbers (if you don't mind the wait of course).

tl;dr

Note: this is definitely not a "reason" to switch programming languages, but one of our (totally unscientific) reasons for deciding to investigate other options for programming languages was the fact that JavaScript (with the introduction of ES2015) now has Six Ways to Declare a Function: https://rainsoft.io/6-ways-to-declare-javascript-functions/ which means that there is ambiguity and "debate" as to which is "best practice", Go, Elixir and Rust don't suffer from this problem. Sure there are "anonymous" functions in Elixir (required for functional programming!) but there are still only Two Ways to define a function (and both have specific use-cases), which is way easier to explain to a beginner than the JS approach. see: http://stackoverflow.com/questions/18011784/why-are-there-two-kinds-of-functions-in-elixir

Further resources:

learn-elixir's People

Contributors

andrewmacmurray avatar asntc avatar carloslfu avatar changjoo-park avatar cleop avatar debck avatar finnhodgkin avatar fusillicode avatar hyprstack avatar iifeoluwa avatar iteles avatar jackcarlisle avatar jay-meister avatar jruts avatar jujumilk3 avatar katbow avatar luchoturtle avatar markhu avatar mcade avatar ndrean avatar nelsonic avatar nielsbom avatar pathway27 avatar reergymerej avatar robstallion avatar rohduggal avatar sciencefidelity avatar simonlab avatar sumanp avatar wyugue avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

learn-elixir's Issues

How to Monitor Dependencies in Elixir Projects using "HexFactor" :-)

In node-land we use the fantastic https://david-dm.org by fellow dwyler @alanshaw to monitor our dependencies ... ❀️ βœ…
see: https://github.com/dwyl/repo-badges#what

In the elixir-verse the tool for monitoring Hex dependencies appears to be "Hex Factor": https://beta.hexfaktor.org by @rrrene (brilliant project name BTW!) creator of many awesome elixir module including credo so fairly certain it's going to be superb! πŸš€

Yes, it's "Beta" so get in early to help debug! πŸ”

authorise hexfactor

We're tracking 3 repos:
image

Deps Status

More to come! πŸ‘

Learn Functional Programming with Elixir by Ulisses Almeida

Not quite a book for absolute beginners, but most certainly a level or two down in difficulty and preparation than the Dave Thomas' book "Programming Elixir". It will be a useful book to learn the micropatterns ( see micropatterns article and micropatterns video) of functional programming for those needing to learn it, but not of the desire to go off to Scheme Land.

Here the author, Ulisses Almeida, compares within the Elixir forum the main differences between his text and that of Dave Thomas:

In Programming Elixir by Dave, he will guide you through all Elixir feature showing you some concepts of functional programming, concurrent programming, and testing. The book is for experienced developers. In Learn Functional Programming with Elixir by Ulisses (what me?), it will guide you only though functional concepts and show you Elixir. The book is for beginners, then a lot of examples will be step by step.

A good example is the "recursive functions" subject. In Programming Elixir you'll have ten pages that describe the recursive function and quickly jump to lists navigation, high order functions, and tail call optimization. In Learn Functional Programming With Elixir, we have entire a chapter with more than 20 pages about recursive functions. You'll see bounded and unbounded recursion, decrease and conquer, divide and conquer, tail call optimization, and anonymous recursive functions. Then, we have another chapter with more than 20 pages to explain high-order functions, giving you several examples from simples lists operations to lazy computation.

I'll hope this explanation help you understand the difference between the two books.

For further information on the necesssary preparation, here is a passage from the beginning of the book:

This book was tailored for beginners in functional programming and Elixir. I expect you have some experience in building simple algorithms, debugging errors, running commands in terminal, and an entry-level knowledge of software development. Any experience in others languages will help you out. You don’t need to be an expert because we’ll start from the scratch.

If you are an object-oriented programmer ready to take the next step, or a college student graduating and looking for a language to work with, this book is for you. If you tried to program in Elixir before and have had a hard time because of the functional programming concepts, this book will teach you the missing knowledge that you need to become a future expert. If you’re already an Elixir or functional programming expert, you may find some valuable tips here, but this book probably isn’t for you.

My basic feeling is that those who have already done some prior Elixir study would be more than enough prepared to tackle this text. It will hopefully solve the problem of having to learn the basic Elixir functional programming patterns so as to then go on to Phoenix, and has a fuller discussion of the use-cases of pattern matching than is found within the free resources. Too, it is written from the point of view of teaching those for whom functional programming is not the first paradigm they were introduced to, so includes within its audience those for whom Javascript was their first exposure to programming.

Yeah! That is all.

String.to_atom errors

If you are liberal with where you are calling String.to_atom you should be weary that:

"Currently Elixir does not support the conversion of strings that contain Unicode codepoints greater than 0xFF."

That means that if you run String.to_atom on a string containing a ’ mark (for instance), it will error.

To fix this, when converting to an atom you could convert all of these quote marks to valid ' marks and filter out everything else that would cause an error.

You could write the following:

@doc """
  iex>safe_to_atom("hi’hi")
  :"hi'hi"
  iex> safe_to_atom("hello")
  :"hello"
"""
def safe_to_atom(string) when is_binary(string) do
  string
  |> String.replace("’", "'")
  |> String.to_charlist
  |> Enum.filter(&(&1 <= 255))
  |> to_string
  |> String.to_atom
end

*single* edeliver command to build and "hot upgrade" a Elixir/Phoenix App?

#as part of using Travis to Continuously Deploy our Elixir Apps using Travis-CI
we are on a quest to find a single command that we can run when a build passes

mix edeliver build upgrade --auto-version=git-revision --from=$(git rev-parse HEAD~) --verbose 
mix edeliver deploy upgrade to production --version=$(git rev-parse HEAD~) --verbose

image

relates to / depends on: #53
... we want to curl app.net/_version instead of reading it from
required by: dwyl/learn-travis#22

Todo

  • keep investigating until we find the magic command to "hot upgrade" an Elixir app! πŸ”
  • Use latest available version of the app when deploying

I've read through all the docs https://github.com/edeliver/edeliver
& wiki https://github.com/edeliver/edeliver/wiki without any luck.
This looks like a good place to continue the quest:
http://www.east5th.co/blog/2017/01/23/upgrade-releases-with-edeliver/

Right now the process requires human intervention to manually type/input the version:
image

Also, it doesn't help that my internet connection keeps timing out because people are clearly using it for (non-work related) streaming ...!
image

Syntax preferences

What should be our syntax preference in these scenarios? Is it important?

Strings

String.contains "longer string" "string"

vs

"longer string" =~ "string"

Maps

list = ~w(one two three)

vs

list = ["one", "two", "three"]

Elixir Concurrency Model

Simple example of the Elixir Concurrency Model and how to handle blocking processes.

Paste the below code into a file called concurrency_demo.ex and run
$ elixir concurrency_demo.ex to run the example locally

defmodule Log do
  defp log(arg), do: IO.puts arg
  def first, do: log "first"
  def second, do: log "second"
  def slowfirst do
    :timer.sleep(1000)
    first()
  end
end

IO.puts "RUN 1"
Log.slowfirst()
Log.second()

# Outputs:
# $ RUN 1
# $ first
# $ second

# In "RUN 1" we see that `slowfirst` blocks `second` from running

IO.puts "RUN 2"
task = Task.async(fn -> Log.slowfirst() end)
Log.second()

# Outputs:
# $ RUN 2
# $ second
# $ first

# But in "RUN 2" we start `slowfirst` and then carry on with the script

Task.await(task) # If you don't assign task and `await`, the program will finish and you won't see the log

Background links section takes you away from tutorial

The first two background links here are:

If I'm minimally methodical about following the tutorial, these two links will take me into a separate world of learning about elixir away from the tutorial, the content of which is also part of the things that come next in the tutorial itself (installation, interactive mode and functional docs).

I would suggest that the two interview links should be left in the background links section but that the two at the top of this issue are interspersed throughout the issue wherever it makes more sense (they are not background reading but the actual content of the tutorial).

Truthiness in Elixir

Currently there's no reference to truthiness in the readme. Given the prevalence of cond and conditional statements in Elixir I think think it would be good to add a reference to the top of Basic types. A few of the tutorials I followed at the start of my Elixir journey didn't talk about truthiness. It definitely negatively impacted my learning, especially coming from JS.

Truthiness in Elixir

All values / types in Elixir apart from nil and false are truthy:

if 0 do "This is happening" end # "This is happening"

if "False" do "This is still happening" end # "This is still happening"

if false do "Not happening" end # nil

Read Git Revision (Hash) in Elixir

I would like to display the git revision hash when visiting a url in an application
so that everyone on the project knows exactly which version of the app
is in "staging" or production.

e.g visiting: https://www.healthlocker.uk/_version
image
healthlocker/healthlocker@cc66a3c

Note: currently visiting this url shows an error page:
image

We made the Git Revision available in dwyl/aws-lambda-deploy/lib/utils.js#L80-L81
So it's a matter of running a similar command in Elixir and returning that when visiting the route.

Todo

  • run an Elixir command/script to get the git revision
  • create a route in basic Phoenix app that returns the git revision
  • determine if the git revision is available in an elixir app that has been deployed with edeliver (I don't see a reason why not, we need to be certain)

Shortcut syntax for key/value pair lists and maps used in this tutorial

In most beginner learning resources I have seen, map literals are presented as:

  animal = %{
     :name => "Rex",
     :type => "dog",
     :legs => 4
}

In this repo, we dive straight into using the shortcut for key/value maps (https://github.com/dwyl/learn-elixir#maps).

animal = %{
  name: "Rex",
  type: "dog",
  legs: 4
}

My understanding is that whilst this is the most common usage, it's also only able to be used if the keys are atoms. Is it worth mentioning that this is a possible syntax so that beginners who see other resources are not confused?

Styleguide

What guide should we follow for our syntax guidelines?

From the ambiguity of syntax guidelines here, deciding on a style guide (or a few style guides) may be a good idea

I would love to follow this one: https://github.com/christopheradams/elixir_style_guide

It looks popular, clear and strict and has the ability to link to each syntax decision which is nice.

Udemy "The Complete Elixir and Phoenix Bootcamp"

In order to learn Elixir and Phoenix I'm using the udemy course "The Complete Elixir and Phoenix Bootcamp", and at the moment I'm really enjoying it! It is also reduced to Β£15 at the moment if dwyl wanted a copy of the course to use.

I found the description and examples of pattern matching especially helpful as this was something I was struggling with understanding through the Elixir School book.

I'm only on the third section right now, but I hope to finish the course this week, at which point, assuming I still like it, I'd like to make a PR to add it as a link in the "Further Resources" section.

Real examples

I don't know if this is suitable for this repo...

I have been doing some codewars on elixir and thought it would be good to show a few simple problems in this learn-elixir repo, and briefly cover a couple different solutions to each one. I hope that it would provide the reader with more structured intro to the language that they can practice by doing.

Does it sound suitable?

How to display HTML code snippets in your elixir code without it rendering

HTML entities can be used to help you display code snippets without them rendering as the code they represent. For example:

Is actually written in the code as:

<code>
  &lt;%= component &quot;primary_button&quot;, value: &quot;I'm a Primary Button&quot; %&gt;
</code>

Where &lt; represents the less than or < symbol etc.

Rather than encoding your hard code and pasting it in statically, how can I dynamically encode my regular code into HTML entities so that I don't have to keep on updating/changing it as my code changes? I want to create a function that will read the contents of a file and then encode its contents so that this will update whenever the file is updated.

Encoding your code
At first I considered regex or some other form of replacement function however this would be complicated to cover all possibilities. So instead I came across the hex package:

https://hex.pm/packages/html_entities

To install the hex package add {:html_entities, "~> 0.3"} under deps to your mix.exs file and run mix deps.get.

Reading the contents of a file
Now that I can encode my code, I now need to be able to grab the code from within a given file in order to encode it. To do this I can use the File module like this:

File.read!("./web/templates/component/primary_button_example.html.eex")

This only works with the trailing bang ! otherwise it errors. This is because we want it to return the code to us, without the ! it will return a tuple instead.

So this function is now called where I want the code snippets to appear in the html file like this:

The function contains:

And on the browser we see:

Despite the availability of the hex package, it turns out that using File.read! I don't even need it.

πŸ˜€

Relates to mindwaveventures/good-thinking-phoenix#115

Difference between tuples and lists

According to the readme:

Tuples are similar to lists except the items are stored in order

Which suggests that items in a list are not stored in order.

[Video] Content to include initially

For the sort of MVP of the videos I think we should make a small amount of content which covers some of the basics of Elixir to see how well the videos are received. Content I think would be good to cover:

  • Use of iex
  • types of values in elixir
  • using the elixir documentation and how awesome it is
  • commonly used code modules (Enum etc)
  • case, cond, if and unless
  • guards
  • pattern matching (including pattern matching in case statements)
  • creating projects with mix
  • documentation in elixir
  • testing in elixir, including doctests

I think these would be a good basis and be enough content that someone could go and play with Elixir. Some of this stuff (testing/doctesting and documentation) is not included in any of the free videos that I've seen on Elixir, and testing and documentation are both super important to us at dwyl so I think they are a must have.

Any suggestions of other content to include in the first series of the videos?

Developing with Elixir [online course]

A Pragmatic Studio course about Elixir was released yesterday. It cost $49 with the early access, and also there is a discount of 15% with the coupon code "elixir-early".

Here is the link to the course.

Edit README to be more concise and ordered more chronologically

Currently the README is not far off 4000 words and from my own experience I found this, combined with the order in which topics are displayed/introduced a bit confusing when knowing where to start.

I am proposing to edit down the text a little (not to lose meaning but simply to make things more concise). As well as thinking about the order things appear, e.g. moving some of the longer video content which is about other topics such as phoenix lower down. It's not that this content isn't useful (hence not removing it), it's just that if you're trying to learn Elixir, you probably want to understand the basics of the language before you leap into phoenix.

I will make sure that people know that there is more content for them that may be of interest by making sure its included in the contents.

I think these changes could help improve people's learning experiences by helping them to learn the bits of elixir they need faster.

How much clarity is needed for beginners?

Should we assume Elixir is unlikely to be someone's first attempt beyond a simple understanding of the basics?

I'm wondering how much we need to add small notes to clarify things like for example what an enumerable is here:

Lists are enumerable, the Enum module provides lots of useful functions.

Or:

  • What an anonymous function is
  • The Elixir / syntax for named functions
  • What a macro is

[Video] Do we need to introduce Elixir from the bare basics?

In the learn-elixir README we give installation instructions and the links to some (awesome) videos and a link to elixirschool.com to get the user acquainted with what Elixir is.

Do we need to have an introduction to what Elixir is in our own videos, or should we just suggest that the user watches the videos/reads the material linked in the README? I suppose it depends on whether we want these videos to be able to completely stand on their own, or to be an accompaniment to the README of the learn-elixir repo.

I can see arguments for both so am keen for input!

What does 'enumerable' mean?

Lists are enumerable, What does enumerable mean?

Is the meaning of enumerable that you can refer to a value by numerical reference (by counting from left to right)?

Say I have a list: ["a", "b", "c"], the numerical reference/ index of a would be 0, b = 1, c = 2?

I've looked at dictionary definitions as well as this forum question: http://softwareengineering.stackexchange.com/questions/199592/what-does-enumerable-mean and can't tell if it's more complex than my original assumption.

Extend README Documentation

Currently the README.md gives a good introduction by covering the basics. I feel as though this should be extended further to include more things integral to a functional programming language:

  • immutability
  • recursive functions
  • partial application
  • heads and tails

Does anyone have any thoughts on things to include?

Initial list of topics to add or extend within the documentation:

  • Generating an elixir project
  • Object Oriented vs Functional
  • Native Modules
  • Module Documentation
  • Testing
  • Pattern Matching - extend #57
  • Elixir -> Erlang -> BEAM
  • Pipe Operator
  • Maps
  • Keyword Lists
  • Structs

Question: Try elixir level 2 ( Making function calls easier to read )

Just finished the level 2 but i still have some doubts:

Exercise:

defmodule Person do
  def format_name(full_name) do
    format(String.split(full_name))
  end
end

Solution:

defmodule Person do
  def format_name(full_name) do
    full_name
      |> String.split
      |> format
end

We use the pipe operator to clean up our code and to facilitate maintaining and reading the code (no doubts here) my question is:

Is there a correct order to "divide" a function using the pipe operator?

Are there some more recent tutorials that should be included?

In the 'What?' section of the tutorial, there is Jessica Kerr's Why Elixir Should take over the world which is a great general talk on Elixir for context and then a video intro to Elixir (which covers some of the same ground as both Jessica Kerr's talk and this learning resource) from March 2014: https://www.youtube.com/watch?v=lly-1UYmnFI&feature=youtu.be

With the momentum behind Elixir, are there any more recent videos that are also maybe also a bit more practical that we can include/replace here?

Erlang Moocs by Simon Thompson (Functional Programming Guru Extraordinare!)

Yeah it is in Erlang, but at this introductory level, the mooc should still be useful as a well put together video course to supplement other resources.

  1. Functional Programming in Erlang: video and assignments

  2. Concurrent Programming in Erlang: Future Learn Note that the materials for this course are only going to be available for about two weeks, so if the course is of interest, the time to act is narrowing.

Simon Thompson teaches at the University of Kent, and so part teaches functional programming for a living, as well as being on first name of basis with the likes of Joe Armstron who is one of the creators of Erlang, upon which Jose Valim built Elixir It is good to get the information from the mouth of the horse, yes?

The Elixir docs have a very nice page on Elixir/Erlang syntax, but as I have said, and this introductory level, it is the explanations and examples and applications of concepts that I am personally looking at.

Evening all!

Video to accompany this repo

After the discussion in #56 about there not being a free/bought video series for Elixir (there is a subscription based one on codeschool.io, and a free intro, but both are very basic, and the bought one on udemy, but see the discussion in #56 ) I think it would be great (after a suggestion from @iteles) to have a video/series of videos accompanying this repo!

I'm not sure how we could actualise this, but I'd love to be involved, any ideas?

Simple but *practical* explanation of pattern matching

Pattern matching is one of the core things to understand in Elixir, but I'm yet to find any really good explanations of pattern matching.

Most give you very basic implementations like https://elixirschool.com/en/lessons/basics/pattern-matching/#match-operator, which are ok but leave beginner with very little to build on.

What other things can be done with pattern matching? How is it useful in a live app?
Can we add more advanced examples later in the tutorial?

Joy of Elixir: Free Online Book

An "absolute" beginner guide to Elixir, fills a gap in the market, and appears to be a work in progress: Joy of Elixir . From first impressions it feels a little bit like "Learn You a Haskell for Great Good" but for, uhm, Elixir.

brew install elixir -> fails

Following the "Official" instructions: http://elixir-lang.org/install.html#mac-os-x
Attempting to install elixir on MacBook Air running OS X 10.12 using brew install elixir
we get the following error:

brew-install-elixir-fails

Warning: You are using OS X 10.12.
We do not provide support for this pre-release version.
You may encounter build failures or other breakages.
==> Installing dependencies for elixir: libtiff, wxmac, erlang
==> Installing elixir dependency: libtiff
==> Downloading http://download.osgeo.org/libtiff/tiff-4.0.6.tar.gz
Already downloaded: /Users/Admin/Library/Caches/Homebrew/libtiff-4.0.6.tar.gz
==> Downloading https://mirrors.ocf.berkeley.edu/debian/pool/main/t/tiff/tiff_4.0.6-1.debian.tar.xz

curl: (22) The requested URL returned error: 404 Not Found
Trying a mirror...
==> Downloading https://mirrorservice.org/sites/ftp.debian.org/debian/pool/main/t/tiff/tiff_4.0.6-1.debian.tar.xz

curl: (22) The requested URL returned error: 404 Not Found
Error: Failed to download resource "libtiff--patch"
Download failed: https://mirrorservice.org/sites/ftp.debian.org/debian/pool/main/t/tiff/tiff_4.0.6-1.debian.tar.xz

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.