1
$\begingroup$

I'm new to Mathematica, coming from an R and Python background, I need to use Mathematica for my thesis. I have been trying to use Return[] like I'd use return() if I needed to in R. In my practice I tried to construct a function that returns the divisors of a number x. I wrote it as follows (trying to adapt my R code from when I was learning R):

HomemadeDivisors[x_] := (a = {1}
Do[If[x/i == Quotient[x, i], a = Join[a, i], ] , {i, 2, x}]
Return[a]
)

Now I'm sure there are plenty of other things that are wrong with how I did it, but bear with me.

I try running (with expected result given below):

HomemadeDivisors[4]
> {1, 2, 4} ## Expected result

Instead I got this:

{Null Return[{Null Return[{Null Return[{If[
        Mod[c If[
            Mod[If[Mod[
                If[{Mod[Return[2], 2], Mod[2 Return[2], 2], 
                Mod[3 Return[2], 2]} == 1, b[[a/2 + 0.5]], 
                1/2 (b[[a/2]] + b[[a/2 + 1]])] Return[c], 2] == 1,
                 b[[a/2 + 0.5]], 
                1/2 (b[[a/2]] + b[[a/2 + 1]])] Return[c], 2] == 1,
             b[[a/2 + 0.5]], 1/2 (b[[a/2]] + b[[a/2 + 1]])], 2] ==
          1, c = b[[a/2 + 0.5]], 
        c = 1/2 (b[[a/2]] + b[[a/2 + 1]])] Return[c], 
      2 If[Mod[
          c If[Mod[
              If[Mod[If[{Mod[Return[2], 2], Mod[2 Return[2], 2], 
                Mod[3 Return[2], 2]} == 1, b[[a/2 + 0.5]], 
                1/2 (b[[a/2]] + b[[a/2 + 1]])] Return[c], 2] == 1,
                 b[[a/2 + 0.5]], 
                1/2 (b[[a/2]] + b[[a/2 + 1]])] Return[c], 2] == 1,
             b[[a/2 + 0.5]], 1/2 (b[[a/2]] + b[[a/2 + 1]])], 2] ==
          1, c = b[[a/2 + 0.5]], 
        c = 1/2 (b[[a/2]] + b[[a/2 + 1]])] Return[c], 
      3 If[Mod[
          c If[Mod[
              If[Mod[If[{Mod[Return[2], 2], Mod[2 Return[2], 2], 
                Mod[3 Return[2], 2]} == 1, b[[a/2 + 0.5]], 
                1/2 (b[[a/2]] + b[[a/2 + 1]])] Return[c], 2] == 1,
                 b[[a/2 + 0.5]], 
                1/2 (b[[a/2]] + b[[a/2 + 1]])] Return[c], 2] == 1,
             b[[a/2 + 0.5]], 1/2 (b[[a/2]] + b[[a/2 + 1]])], 2] ==
          1, c = b[[a/2 + 0.5]], 
        c = 1/2 (b[[a/2]] + b[[a/2 + 1]])] Return[c]}]}]}]}

Some of this looks like code from another function I've tested unsuccessfully, but that isn't the core problem, because when I try Divisors[4] it gives me exactly the result I want without any of this garbage. So what's the problem? I'm guessing the problem is with the Return[] statement since when I rewrote another function to remove the Return[] statement the problem disappeared, but sometimes I like for the sake of my sanity to use return statements. Any guesses of what I'm doing wrong?

$\endgroup$
4
  • 1
    $\begingroup$ You’re missing a semicolon after a = {1}. $\endgroup$ – Chip Hurst Aug 31 '18 at 3:14
  • 2
    $\begingroup$ Related: (29353), (171037), (151129) $\endgroup$ – Carl Woll Aug 31 '18 at 4:08
  • $\begingroup$ Your question may be put on-hold as it's considered off-topic to keep forever questions that result from simple syntax mistakes, easily found in the documentation. That doesn't mean that your questions are not welcome, do not be discouraged by that cleaning-up policy. Learn about common pitfalls here. Learning about asking and what's on-topic will help you next time. Your future good questions are welcome. $\endgroup$ – rhermans Aug 31 '18 at 16:13
  • $\begingroup$ I urge you not to use Return "for your sanity". It does not work the way you imagine it to work (it's complicated). Mathematica is not a programming language in the sense you're trying to use it: it is an expression rewriting system. Sometimes the rewrites resemble what you get from a procedural programming language, but there are many gotchas. Look to learn Mathematica on its own terms. Trying to adapt code from another language is the path to much frustration. $\endgroup$ – John Doty Aug 31 '18 at 23:17
3
$\begingroup$

Obviously, you could use the built-in Divisors, but that will not tell you how to write a function in Mathematica. There are several issues with the function you wrote, so we will take them one at a time.

First, a carriage return does not act as a delimiter between the different statements. Well, that is mostly true. In the notebook environment, it can be interpreted as a delimiter, but within the body of a function, it is not. In other words, within a single cell

someThing
someThingElse

are considered separate statements. But,

(someThing
someThingElse)

is interpreted as

Times[someThing, someThingElse]

because the parentheses force the notebook interface (the Front End or FE for short) to interpret is a compound statement. So, you need to use a semi-colon, ;, to separate the statements, e.g.

(someThing;
someThingElse)

which is interpreted as

CompoundExpression[someThing, someThingElse]

Second, you use the variable a, but as written it should be local to the function, so we can scope it using Module, e.g.

HomemadeDivisors[x_] :=
 Module[{a = {1}},
  Do[If[x/i == Quotient[x, i], a = Join[a, {i}]], {i, 2, x}]; 
  a
 ]

You will note that I used a comma to separate {a = {1}} from the rest, that is because Module accepts two arguments: the first being the scoped list and the second being the body to execute. This is where the semi-colon comes into play as it is transformed into a single CompoundExpression that can serve as the second argument to Module. Also, I fixed the second argument to Join as it takes lists.

Third, Return is a peculiar function and not necessary here. The example given in the documentation is to perform an early return from the function, but there are cases where that is not effective. It is not needed here because the result of body is the return value of Module because every function has a return value, including CompoundExpression which returns the result of the last expression in it. Note: Do, For, and While return Null, so other mechanisms must be used to get results out of them, like you did in updating a or using Return. For the most part, there are other functions that perform the same tasks as Do, For, and While, like Table, Array, Nest, etc., but have better return values. They do have their uses, though.

$\endgroup$
4
  • $\begingroup$ This is a stupid question maybe... but you have to specify that variables in a function are local? Is there a reason for that? $\endgroup$ – William Bell Sep 1 '18 at 4:53
  • $\begingroup$ @WilliamBell you don't, but it's global, then. So, if any other functions use it, then they could be adversely effected. Of course, this could be completely intentional, too. If it is not, it's good practice to restrict variables to the minimum scope that they're needed for. This prevents unwanted side-effects. $\endgroup$ – rcollyer Sep 1 '18 at 11:12
  • $\begingroup$ Sorry I was more confused as to why it doesn't default to local, does the language have a reason for that? $\endgroup$ – William Bell Sep 1 '18 at 17:55
  • $\begingroup$ @WilliamBell the named variables in the rhs of Set/SetDelayed are local, otherwise it's like most other languages, they have to be explicitly localized. Also, there are several different localization constructs, and they're worthwhile examining. $\endgroup$ – rcollyer Sep 1 '18 at 20:24
1
$\begingroup$

The whole point of using Mathematica is to avoid having to write code for basic functions. Instead, just use the built-in function:

Divisors[n]

For instance:

Divisors[4]

{1,2,4}

$\endgroup$
2
  • 1
    $\begingroup$ Clearly the OP is trying to learn Mathematica by creating his own version of function with known output. The question was "So what's the problem?". $\endgroup$ – rhermans Aug 31 '18 at 16:08
  • $\begingroup$ I note the existence of Divisors[] in my original post, this is pedagogical. I even use the exact same example of Divisors[4]. $\endgroup$ – William Bell Sep 1 '18 at 4:36

Not the answer you're looking for? Browse other questions tagged or ask your own question.