1
\$\begingroup\$

I just started learning Elixir and stumbled upon this challenge over on Programming Puzzles & Code Golf. It is a well-suited task for beginners, so I chose to give it a go (to be clear, give it a go means solve it normally, not golfing it). To keep this question self-contained, here is the task – citing the linked post:

For a given positive integer \$n\$:

  1. Repeat the following until \$n < 10\$ (until \$n\$ contains one digit).
  2. Extract the last digit.
  3. If the extracted digit is even (including 0) multiply the rest of the integer by \2ドル\$ and add \1ドル\$ ( \2ドルn+1\$ ). Then go back to step 1 else move to step 4.
  4. Divide the rest of the integer with the extracted digit (integer / digit) and add the remainder (integer % digit), that is your new \$n\$.

For example, \61407ドル\$ gives \5ドル\$ when ran through this mechanism. I've come up with the following code:

defmodule ExtractAndDivide do
 def extract_and_divide(x) do
 if x < 10 do x
 else
 head = div x, 10
 tail = rem x, 10
 case rem tail, 2 do
 0 -> head * 2 + 1 |> extract_and_divide
 1 -> div(head, tail) + rem(head, tail) |> extract_and_divide
 end
 end
 end
end

I'm seeking general advice, but mainly focusing on the following:

  • Naming and Syntax better practices (usage of parenthesises, variable names etc.)
  • Usage of |> (pipe) in this context. Would you ever see it used the way I did it in production code? Should I switch to "normal" notation instead?
  • Less verbose or more elegant way to avoid the seemingly unaesthetic if x < 10 do x ... else ... end structure, perhaps using case would be better here?
  • Is recursion the way to go? Should I stick to it or are there better, equivalent methods?
asked Sep 3, 2018 at 13:54
\$\endgroup\$
1
  • \$\begingroup\$ Since both clauses in your case end with the same pipe you could pipe the case. Have the 0 case just return head*2+1 and put the pipe after the case's end. \$\endgroup\$ Commented Mar 18, 2020 at 21:30

2 Answers 2

1
\$\begingroup\$

I do not have much to say about the pipe operator. It looks fine to me, although maybe some else has something to say...

As for the if-else clause, you can use cond. It is basically a stylized if statement that looks like a case statement. One of your conditions can be x < 10 -> and the other default statement would be true ->.

I am not entirely sure if this is the best practice since the wording is a bit ambiguous in the documentation. Under the use case for cond it says the following:

This is equivalent to else if clauses in many imperative languages (although used way less frequently here).

Which I interpret to be else if clauses are used less often (implying that cond is often preferred).

answered Sep 3, 2018 at 21:35
\$\endgroup\$
2
\$\begingroup\$

(untested)

defmodule ExtractAndDivide do
 def extract_and_divide(x) when x < 10, do: x
 def extract_and_divide(x) do
 head = div x, 10
 tail = rem x, 10
 up_or_down = rem tail, 2
 go_up_or_down(head, tail, up_or_down)
 end
 defp go_up_or_down(head, tail, up_or_down) when up_or_down == 0 do
 extract_and_divide(head * 2 + 1)
 end
 defp go_up_or_down(head, tail, _up_or_down_is_one) do
 extract_and_divide(div(head, tail) + rem(head, tail))
 end
end

The idea with having multiple conditional function clauses is twofold: it reduces nesting (and thus should increase readability), and - quite powerful - it allows to to easily test individual conditional parts. Whether to make the recursive call to extract_and_divide by piping the calculation through the function invocation or directly (like I did purely to show the alternative) is largely a matter of taste.

(note: skipped/circumvented potential nitpicking around naming and whether up_or_down shouldn't be a boolean; I just wanted to illustrate the pattern of doing logic by using multiple function heads)

answered Sep 19, 2018 at 13:46
\$\endgroup\$
1
  • \$\begingroup\$ The separate head to handle the x<10 case is good. The first function head for go_up_or_down could be simpler: defp go_up_or_down(head, tail, 0) do. There is no need to use a when clause for an exact match. \$\endgroup\$ Commented Mar 18, 2020 at 21:28

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.