Sounds good AJ. I already have the Introducing Elixir book, that seems as good a place to start as any.
Join the club
Sounds like a plan
Sounds good AJ. I already have the Introducing Elixir book, that seems as good a place to start as any.
Join the club
Sounds like a plan
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: chrismccord
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.
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:
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
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
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
/Btw - I merged both threads. Should make it easier keep track of stuff/
I really love the |>
(pipe) construct.
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)
.
Add guards to that and the fact that you can do this with even more complex stuff
Haven’t got to guards yet
I thought pipes were cool too
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?
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
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?
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
Good point - I forgot that haha.
I don’t mind the // just wondered what the thinking was behind it.
^^ still the other way around
Whoops! I can see that happening quite often
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 I reckon they could have called it `eli’ instead - Eli the interactive elixir
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:
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
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
.
I have a masters degree in computer science. We used SML for learning about functional programming. Elixir was easy going from Ruby.
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.