Hi,
I am wondering why my solution wil not work
2. solution attempt:
@spec classify(number :: integer) :: {:ok, atom} | {:error, String.t()}
def classify(number) do
case aliquot_sum(number) do
number -> ok(:perfect)
x when x > number -> ok(:abundant)
x when x < number -> ok(:deficient)
end
end
defp ok(item), do: {:ok, item}
defp aliquot_sum(number), do: get_divisors(number) |> Enum.sum()
defp get_divisors(number, divisor \\ 1, acc \\ [])
defp get_divisors(number, divisor, acc) when divisor > div(number,2), do: acc
defp get_divisors(number, divisor, acc) when rem(number, divisor) == 0,
do: get_divisors(number, divisor + 1, [divisor | acc])
defp get_divisors(number, divisor, acc), do: get_divisors(number, divisor + 1, acc)
end
3. question:
Complier is saying:
this clause cannot match because a previous clause at line 15
always matchesElixir
perfect_numbers.ex(15, 7): related
and
variable "number" is unused (there is a variable with the same name in the
context, use the pin operator (^) to match on it or prefix this variable
with underscore if it is not meant to be used)Elixir
Why is that, why it cannot match with number passed to function?
The first case clause matches any number. The clauses’ order matters.
But I used the same variable name in function clause, so I would expect that It would match against it
Oh, I get you now. You can use the pin operator ^number
.
1 Like
No, your logic is wrong and number might not be what You think…
As soon as there is a match, the rest of the case is discarded
the number in the case is not the number parameter, it is a new number
You probably should write this with cond
aliquot = aliquot_sum(number)
cond do
aliquot > number -> ...
aliquot < number -> ...
aliquot == number -> ...
end
1 Like
After adding ^ operator it’s right why should I use cond? What is more “idiomatic” whatever this “idiomatic” word mean? 
Because it’s very rare to use ^number in the case 
Yet, You can do as You like
In my experience it’s very rare to use cond
but it’s still valid.
Last question, i cannot find explanatio why this works that way. Do you have explanation or link to resources?
People have a weird aversion to cond
for some reason that I don’t really understand. Doing pure boolean checks is exactly what it exists for. The case
version is essentially the same with unnecessary extra syntax. Using cond
gives added information that indeed all clauses are boolean checks. It’s only rare because this doesn’t come up as often in Elixir, but it certainly does come up!
Ok, I get it, but the question was, why it was not working with case this, matching why do we have to use this ^ pin operator?
Oh sorry wasn’t responding specifically to your question.
But to answer it: Elixir allows variable re-binding, ie, you can say: number = number+ 1
and not get an error that number
is already defined. Like =
, ->
is also a binding operator, so when you say number -> ok(:perfect)
, number
is rebound. The match on the value of number
, you need to use the pin operator.
1 Like
This form rebinds the name number
inside the case branch:
def some_fun(number) do
case 2*number do
number ->
# number here is bound to a new value, shadowing the argument named number
This will match ANY integer passed to some_fun
.
ON THE OTHER HAND
Using the pin operator says “match this existing value”:
def some_fun(number) do
case 2*number do
^number ->
# number here is still bound to the argument
That will only match if some_fun
is passed 0, since 2*0 == 0
2 Likes