Elixir


#22

Sounds good AJ. I already have the Introducing Elixir book, that seems as good a place to start as any.

Join the club :smile:

Sounds like a plan :thumbsup:


#23

Awesome - what’s it like? How far you into it? I just bought it btw, apparently Elixir in Action is quite advanced.

This looks like a good video: http://www.chrismccord.com/blog/2014/05/27/all-aboard-the-elixir-express


#24

I just started reading it. Will get into it over the weekend and post some feedback next week.

That video quite sold it to me, too.


#25

I find that I get around a language enough for a starters with Project Euler.

I’ve solved a couple of the firsts problems with Elixir. I’ll give the first two away, just so you guys can see how it works:

Problem #1

If we list all the natural numbers below 10 that are multiples of 3 or 5, we get 3, 5, 6 and 9. The sum of these multiples is 23.

Find the sum of all the multiples of 3 or 5 below 1000.

defmodule Problem1 do
  def result do
    1..1000
    |> Enum.filter(&multiples_of_three_of_five/1)
    |> Enum.reduce(0, &+/2)
  end

  defp multiples_of_three_of_five(n) do
    rem(n, 3) == 0 || rem(n, 5) == 0
  end
end

IO.puts Problem1.result

Problem #2

Each new term in the Fibonacci sequence is generated by adding the previous two terms. By starting with 1 and 2, the first 10 terms will be:

1, 2, 3, 5, 8, 13, 21, 34, 55, 89, …

By considering the terms in the Fibonacci sequence whose values do not exceed four million, find the sum of the even-valued terms.

defmodule Problem2 do
  import Integer, only: [is_even: 1]

  def result do
    Stream.iterate(0, &(&1+1))
    |> Stream.map(&fib/1)
    |> Stream.take_while(&(&1 < 4000000))
    |> Enum.filter(&is_even/1)
    |> Enum.sum
  end

  defp fib(0), do: 1
  defp fib(1), do: 2
  defp fib(n), do: fib(n-1) + fib(n-2)
end

IO.puts Problem2.result

#26

Thanks Ohm - when I looked at that earlier I thought WTF!!?? Haha.

Just read the first two chapters of introducing Elixir and it’s making more sense :slight_smile:

/Btw - I merged both threads. Should make it easier keep track of stuff/


#27

I really love the |> (pipe) construct. :heart:

For those not in the know, the pipe will pass it’s left argument as the first parameter in the right argument, that is

1..10 |> Enum.sum

is the same as

Enum.sum(1..10)

This is awesome when you are doing multiple function calls, like in the above example, where I pass the result of one function directly into the next. With functional programming, you’ll strive to create small functions with one purpose and then reuse that small function.


Another awesome thing is the pattern matching in the parameters. The fib function above shows this nicely. Instead of a big ugly if-statement, we just say "if my first parameter is 0, return 1, if it’s 1 return 2, else return fib(n-1) + fib(n-2).


#28

Add guards to that and the fact that you can do this with even more complex stuff :heartbeat:


#29

Haven’t got to guards yet :stuck_out_tongue_winking_eye:

I thought pipes were cool too :smile:

However, not sure of default values for parameters:

def some_function(one, two // 555) do
end

Where 555 is the default value for two. Any idea why they went for that? I guess cos that’s how Erlang does it?

And how would you add a default value for one too?


#30

For one, it has to be backslashes (\\)

defmodule Test do
  def test(one \\ 555, two \\ 666) do
    IO.puts one
    IO.puts two
    IO.puts
  end
end

Test.test()
Test.test(111)
Test.test(222, 333)

will print:

555
666

111
666

222
333

#31

Any idea why tho, over this:

defmodule Test do
  def test(one=555, two=666) do
    IO.puts one
    IO.puts two
    IO.puts
  end
end

Which do you prefer?


#32

I don’t know, but I would guess that it’s because in Elixir (and Erlang) the = (equal sign) doesn’t mean “this is set to that”, but rather “this must match that”. So your example defines a method called test, which takes only two arguments, namely 555 and 666.

defmodule Test do
  def test(one=555, two=666) do
    IO.puts one
    IO.puts two
    IO.puts ""
  end
end

Test.test(555, 666)

prints

555
666

#33

Good point - I forgot that haha.

I don’t mind the // just wondered what the thinking was behind it.


#34

^^ still the other way around :smirk:


#35

Whoops! I can see that happening quite often :grimacing:

Wonder why they didn’t go for something like

  def test(one/ 555, two/666) do
    IO.puts one
    IO.puts two
    IO.puts
  end

Where the slash directly after a param indicates it has a default value.

I guess they’ve thought about this tho and have the bigger picture in mind (whereas as a nube, I don’t).

Edit: To answer my own question, I think it is because of arity. Where something/1 to Elixir is the name of a function and something/2 is actually considered a different function.

Also, every time I see iex I think of internet explorer :stuck_out_tongue_closed_eyes: I reckon they could have called it `eli’ instead - Eli the interactive elixir :grin:


#36

This is a good video by Prag Dave, but I don’t recommend watching it until after you’ve at least read through the basics of Elixir - the first time I watched it it actually put me off Elixir as I was like omgwtf!

Also, arity in Elixir sounds really neat:


Which other languages interest you?
#37

And remember that some of those functions can be private, so you can have a public is_boolean/1, but a private is_boolean/2. You can use this to write nice tail-recursive functions, like this length function:

defmodule Sequence do
  def len([]),           do: 0
  def len(list),         do: len(list, 0)
  defp len([],       i), do: i
  defp len([_|tail], i), do: len(tail, i+1)
end

#38

I kinda know what’s going on there @Ohm, but could you explain each line for us please?


#39

Sure. In this example:

defmodule Sequence do
  def len([]),             do: 0
  def len(list),           do: len(list, 0)
  defp len([],       acc), do: acc
  defp len([_|tail], acc), do: len(tail, acc + 1)
end

we define a module, Sequence, with two functions, namely len/1 and len/2. len/1 is public, whilst len/2 is private (that’s what the defp is for).

Users of our function can only call len/1 from the outside, doing something like this:

Sequence.len [1, 2, 3]

Underneath we do some magic to make this length function work with tail-recursion.

First we do some pattern matching on the empty list, because the empty list has length 0. (Note, this can actually be removed, but I like it to tell the story)

If the list is not the empty one, we call our own private function, len/2. len/2 takes the list and an accumulator. If the list is empty, we can just return our accumulator as the result. If it’s not, then it must be a head and a tail. The [_|tail] in the pattern means: "A list with something I don’t care about as head and a tail, which is bound to tail". In order to find the length, we remove the head and add one to our accumulator, and then continue finding the length of the tail.


So if we run with our example from before:

Sequence.len [1, 2, 3]

We actually get this:

len([1,2,3])
-> len([1,2,3], 0)
-> len([2,3], 1)
-> len([3], 2)
-> len([], 3)
-> 3

We can remove the first pattern match, like so:

defmodule Sequence do
  def len(list),           do: len(list, 0)
  defp len([],       acc), do: acc
  defp len([_|tail], acc), do: len(tail, acc + 1)
end

because now we will always hit the public function, but as list is the empty list, we will match the first pattern and just return our initial accumulator, which is 0.


#40

Nice one, thanks @ohm :+1:

How long did it take you to learn Elixir or ‘get’ the concepts of it?


#41

I have a masters degree in computer science. We used SML for learning about functional programming. Elixir was easy going from Ruby. :smirk:

I started to look at Elixir about half a year ago. I won’t say that I am a master in Elixir, but I get the concepts.