Message Boards Message Boards

Fix function that doesn't evaluate when passed to a package?

GROUPS:

Hi, I'm baffled by the following...if I define a function in a notebook as follows:

func = Function[x^2][x];

I can call it in the notebook:

Table[func, {x, 1, 6}]
{1, 4, 9, 16, 25, 36}

I can also call it in a function defined in the notebook:

runNb[func_] :=
    Module[{},
        Table[func, {x, 1, 6}]
    ]
runNb[func]
{1, 4, 9, 16, 25, 36}

but, when I try to run this as a package, the function doesn't evaluate:

BeginPackage["run`"]
    run::usage = "run[func]"
    Begin["`Private`"]
        run[func_] :=
            Module[{},
                Table[func, {x, 1, 6}]
            ]
    End[]
EndPackage[]

and, calling from the notebook:

<< run.m
run[func]
{x^2, x^2, x^2, x^2, x^2, x^2}

Makes no sense to me! Can anyone please explain?

Thanks

POSTED BY: Stephan Foley
Answer
2 months ago

Perhaps the local variable x inside the package is not the same as the global variable in the definition of func. Try this:

BeginPackage["run`"]
run::usage = "run[func]"
Begin["`Private`"]
run[func_] := Table[{Context[x], func}, {x, 1, 6}];
End[]
EndPackage[]

and evaluate run[func]. I get

{{"run`Private`", x^2}, {"run`Private`", x^2}, {"run`Private`", 
  x^2}, {"run`Private`", x^2}, {"run`Private`", x^2}, {"run`Private`",
   x^2}}

I don't know what you are trying to achieve with func. The variable x in [x] in Function[x^2][x] does not matter. You get the same output with Function[x^2][y].

POSTED BY: Gianluca Gorni
Answer
2 months ago

Hi Gianlunca and thanks for the reply.

Original problem was I wanted to take a list of functions and pass them into a package which had a plotting function. This did not work, so I started stripping things down and found the core of the problem was that the functions were not evaluating. I had written the functions like so:

funcs = {x^2, x^3, x^4}

I thought it might be because I wasn't explicitly defining an anonymous function, so that's why I used the Function call above.

I did try to use global x in the package like so:

BeginPackage["run`"]
    run::usage = "run[func]"
    Begin["`Private`"]
        run[func_] :=
            Module[{x = Global`x},
                Table[func, {x, 1, 6}]
            ]
    End[]
EndPackage[]

But this didn't help. I think the x is local to the Table block and so should just be replaced in the anonymous function. Either using global x or not shouldn't matter.

POSTED BY: Stephan Foley
Answer
2 months ago

Module does not replace the local variable x in Table:

Module[{x = 3}, Table[x, {x, 0, 2}]]

You can do that with With:

BeginPackage["run`"];
run::usage = "run[func]";
Begin["`Private`"];
run[func_] := With[{x = Global`x}, Table[{x, func}, {x, 1, 6}]];
End[];
EndPackage[];

The way I would define a function and do a table of the values is this, however:

f[x_] := x^2;
BeginPackage["run`"];
run::usage = "run[func]";
Begin["`Private`"];
run[func_] := Table[func[x], {x, 1, 6}];
End[];
EndPackage[];
run[f]
POSTED BY: Gianluca Gorni
Answer
2 months ago

Note that it's a bad practice to use x from Globalbecause (users/you) may be using it for something else and other "bad" packages may introduce further confusion. For this reason when it's necessary to offer convenience to use Global use a LONG NAME (and not something cryptic). However: use of Options[run] is a better way to handle allowing (user) to set variables generally used by parts of a package. Yet another way is to define something outside of Private that can be replaced by user without need of Unprotect[], ex runx (note this can still become a problem with Global).

Note also that your code "could work" (the x inside table will be runPrivatex if you check ?runPrivate*, in general if x does not exist Mathematica will create it - in this case not in Global). If a Private defined function that is also public (outside of Private) takes arguments, the arguments can of course, be functions. However you need to study Context[] closely. It's well likely your problem is a corrupt runtime environment confusing things (you may have Global`run defined and not realize it).

Finally, if you find Mathematica is USING Globalx in the Table (it shouldn't), then use run[func_]:=Module[...]. Also note Mathematica WONT use Globalx if you define x in runor runPrivate.

Study more about Context[]

POSTED BY: John Hendrickson
Answer
2 months ago

@Gianluca thanks for the help, I like what you did with your second piece of code.

@John totally agree about not using Global`x. I find Mathematica's handling of variables pretty frustrating sometimes.

Well, I would say I'm still not happy here. It makes no sense to me that you cannot pass a function defined in a notebook to another function defined in a package. It's just my expectation that the function will evaluate. I don't think using Global`x is the way to go. Although I like Gianluca's second approach, I think it is a workaround and doesn't solve the initial problem.

POSTED BY: Stephan Foley
Answer
2 months ago

Your way to define a function func = Function[x^2][x] is very bizarre. It is totally equivalent to writing

func = x^2

so that it is more an algebraic expression than a function. You cannot write func[2] to get its value when x=2, but you have to do something like func/.x->2 or Block[{x = 2}, func]. Your use of the global variable x is dangerous for various reason.

The usual, elementary way to define a function is this:

func[x_] := x^2

You can also use Function, but the correct syntax would be something like this:

func = Function[x, x^2]

Either way you evaluate func[2] and get 4.

POSTED BY: Gianluca Gorni
Answer
2 months ago

OK, I got everything working now, thanks to Gianluca Gorni. As pointed out, my mistake was how I was defining functions. Even though it was incorrect, it was working in the notebook. New code that is working both in the notebook and with a package follows.

Package is now:

BeginPackage["mypackage`"]
    run::usage = "run[func]"
    Begin["`Private`"]
        run[func_] :=
            Module[{},
                Table[func[x], {x, 1, 6}]
            ]
    End[]
EndPackage[]

and code in notebook is:

<< mypackage.m
func = #^2 &;
run[func]

Thanks for taking the time to help me out on this!

POSTED BY: Stephan Foley
Answer
2 months ago

Group Abstract Group Abstract