Introduction to the Elixir Programming Language


Author: Tyler M. Masthay

CPS 499-03: Emerging Languages, Spring 2017


Key language concepts in Elixir

  • Functional language designed primarily for concurrent, distributed computing
  • Elixir is similar to Ruby and Erlang, especially Erlang
  • Every Elixir program compiles into bytecode for the Erlang Virtual Machine
  • Polymorphism via protocols (main technical inspiration behind Elixir)
  • Use of Actor model for concurrency
  • Like Erlang, designed for creating fault-tolerant systems
  • Developed by José Valim, whose main goal was to improve upon Erlang
  • Standardized project-making, configuration, and documentation tools for fast development
  • Everything is immutable
  • Everything is pattern matched
  • Supports closures (modules)
  • Types are inferrred


Essential Elixir

  • Function types can be user-defined by @spec keyword
  • send and receive
    • Used for processes to communicate back and forth
    • send( recipient, message )
      • recipient: process receiving message
      • message: the message being passed
    • receive
      • Syntax similar to a switch statement
      • receive do msg1 -> response1; msg2 -> response2; ... end
  • Primitive types: integer, float, boolean, atom, string, list, tuple
  • Polymorphic, LISP-like lists but with Haskell-like syntax
  • List operators ++ (append), -- (difference), | (cons)
  • Lambda expressions through fn(x) -> (expr)
  • def prefixes many declarations ( def --- function declaration, defmodule --- module declaration, defprotocol --- protocol declaration )
  • mix command for automatic project generation and configuration
  • |> to create pipes in Elixir command line (equivalent to | in Linux)


Essential types

  • string concatenation: <> (e.g., "Hello" <> " world!")
  • basic arithmetic: + ,-,*,/, - for unary negation
  • comparison operators: ==, === (type and value matching), <, >, <=, =
  • boolean operators: and, or, not, or, &&, ||, !
  • if, case, cond, unless -- case is a switch statement, cond is just like LISP cond, unless is if statement with negation of predicate
  • comments begin with # and multiline comments are not supported

  • Running a progam

  • iex myProgram.ex
  • Configurating a project
     
    mix new projectName --sup
    cd projectName 
    mix test 
     
  • hit CTRL+C followed by 'a' (for "abort") to exit the interpreter

  • Functions

  • Can be declared like in Haskell or with def inside module
    • identity = fn(x) -> x end
      
    • defmodule simpleModule
      	def identity = fn(x) -> x end
      end
      
  • Can be passed anonymously
    • apply = fn(f,x) -> f.(x) end
      apply.((fn(x)->2*x end), 5)
      
  • Curry and uncurry are not built-in functions like in Haskell
  • Functions are not default curried like Haskell
  • Defining a curried function
      add = fn(x) -> fn(y) -> x + y end end  
      add2 = add.(2)
      add2.(3)
      

  • The Actor Model of Concurrency

    • Two basic principles
      • everything is an actor
      • an actor has a mailbox
    • How do those two principles give you recursion?
    • Turing complete
      1. 1. Processing
        2. Storage
        3. Communication
    • Basic actions of Actors
      1. 1. Create more actors (spawn)
        2. Send messages to other actors (send( receivingActor, message ))
        3. Decide what to do with its next message (receive do ... end)


    Actors in Elixir

    • Actors are decoupled
      • they run at their own speed
      • they do not block when they send messages
    • Message mailbox in FIFO order, but message passing is asynchronous
      defmodule Counter do
         def loop(count) do
            receive do
               {:next} ->
                  IO.puts("Current count: #{count}")
                  loop(count + 1)
            end
         end
      end
      
      counter1 = spawn(Counter, :loop, [1])
      counter2 = spawn(Counter, :loop, [100])
      
      send(counter1, {:next})
      send(counter1, {:next})
      send(counter2, {:next})
      send(counter2, {:next})
      send(counter1, {:next})
      send(counter2, {:next})
      send(counter1, {:next})
      
      $ iex Counter.ex
      
      Current count: 1
      Current count: 100
      Current count: 2
      Current count: 101
      Current count: 3
      Current count: 102
      Current count: 4
      


    Exercises

    The following are programming exercises that incorporate essential Elixir concepts:
    • Modify the program Counter2.ex so that a private member variable currCount is printed and modified.

    • Implement a module for a binary tree closure that is purely functional. Use the following representation: a leaf node is a tuple of the form {:leaf, val} where val is the value associated with this tree and an internal node is of the form {:internal, left, right} where left and right are the associated subtrees. Ensure that polymorphics trees are supported. For example, the tree {:internal, {:leaf, 1}, {:leaf, fn(x) -> x}} should be supported within the module.

    • Use the binary tree from problem 2 to implement the foldl and foldr functions from the Haskell programming language.


    References

      [1] 2017. Elixir. Available: http://elixir-lang.org [Last accessed: 29 March 2017]. (2017).
      [2] I. Dees B. Tate, F. Daoud, and J. Moffitt. 2014. Seven More Languages in Seven Weeks: Languages That Are Shaping the Future. The Pragmatic Bookshelf, Raleigh, NC.
      [3] P. Butcher. 2014. Seven Concurrency Models in Seven Weeks: When Threads Unravel . The Pragmatic Bookshelf, Raleigh, NC.
      [4] Sahu, N. "An Interview with Elixir Creator José Valim." SitePoint . SitePoint, 30 Nov. 2015. Web. 18 Mar. 2017.
      [5] C. Hewitt, P. Bishop, and R. Steiger. 1973. Session 8 Formalisms for Artificial Intelligence: A Universal Modular ACTOR Formalism for Artificial Intelligence. In Advance Papers of the Conference , Vol. 3. Stanford Research Institute, 235.
      [6] S.L. Salas and E. Hille. 2016. Erlang and Elixir for Imperative Programmers . APPRESS, New York, N.Y.

    Return Home