5
$\begingroup$

I've been struggling on this problem for quite a while, but I still don't understand why Mathematica is unable to recognize a function definition where the rhs is an Import command.

Let me introduce the problem.

Consider the following Mathematica Package

(*Package v1*)
BeginPackage["test`"]

testFun::usage = "testFun[]";

Begin["`Private`"]

packageDirectory = $InputFileName // DirectoryName;

fModule[] := Module[{},
    f[x_] = Import[FileNameJoin[{packageDirectory,"fun.m"}]];
];

testFun[xx_] := Module[{},
    fModule[];
    Table[f[i], {i, xx}]
];

End[] (* `Private` *)

EndPackage[]

where the file fun.m acts as simple container for the definition of the body of f, e.g.

x^2

When testFun[5] is called in Mathematica Notebook the result is

{x^2, x^2, x^2, x^2, x^2}

which means that the pattern x_ is not recognized when fModule[] is called.

The weird fact is that moving the defintion of f[x] outside the module, i.e. like

(*Package v2*)
BeginPackage["test`"]

testFun::usage = "testFun[]";

Begin["`Private`"]

packageDirectory = $InputFileName // DirectoryName;

f[x_] = Import[FileNameJoin[{packageDirectory,"fun.m"}]];

fModule[] := Module[{},
    f[x_] = Import[FileNameJoin[{packageDirectory,"fun.m"}]];
];

testFun[xx_] := Module[{},
    (*fModule[];*)
    Table[f[i], {i, xx}]
];

End[] (* `Private` *)

EndPackage[]

the definition of f[x] is properly recognized!

Also, everything works if I run the code (Package v1) directly in the FrontEnd!

In my actual code I need the definition of f[x] to happen inside the module using the Import. That's because the expression to be used in the definition is quite big and I prefer to keep it in a dedicated .m file.

Does anyone know why I can't define a function using an Import inside a module? Again, the problem exist in the Package only.

Thanks a lot in advance, and happy new year! :)

Ps: I apologize for the criptic title.

$\endgroup$
9
  • $\begingroup$ Look at the output of ?? test`Private`f - you'll see that the x returned from Import is not in the same context as f $\endgroup$
    – Jason B.
    Commented Jan 3, 2018 at 20:10
  • $\begingroup$ Hi Jason! You're right, the output shows that they are not in the same context: test`Private`f[test`Private`x_]=x^2. $\endgroup$ Commented Jan 3, 2018 at 20:32
  • $\begingroup$ The problem is that when you finally call testFun, you are no longer in the test`Private` context, you are now in the global context. A quick fix is to modify the body of fModule to use f[ Global`x_] = .... . This assumes that when you actually call testFun you will be in the global context. Someone else will have to provide a more robust solution. $\endgroup$
    – Jason B.
    Commented Jan 3, 2018 at 20:34
  • $\begingroup$ Better may be to call BeginPackage and EndPackage inside the Module. As an aside, using Module[{}, ...] is less efficient than just using (...). You're not using Module for scoping so you can drop it. $\endgroup$
    – b3m2a1
    Commented Jan 3, 2018 at 20:48
  • $\begingroup$ @JasonB. thanks for the quick fix, I'll try it on my code soon! @b3m2a1 the Package test is just an example to explain the problem, in my code I really need Module because I have several local variables. $\endgroup$ Commented Jan 3, 2018 at 21:52

1 Answer 1

4
$\begingroup$

The problem, as stated in the comments, is that when you define fModule in the private context of your package,

fModule[] := Module[{},
    f[x_] = Import[FileNameJoin[{packageDirectory,"fun.m"}]];
];

The x symbol will have the FullForm

Pattern[test`Private`x,Blank[]]

but since the file fun.m is read in when the function is called, the x present in that file is parsed as Global`x (or another context depending on when you call the function).

A hack to get it to work would be to redefine the f function to be of the form f[Global`x_], but this is not robust since you could be calling the function from within another package.

A better workaround is to define f as a Function, rather than a symbol with DownValues. In test.m, use

fModule[] := Module[{},
    f = Import[FileNameJoin[{packageDirectory,"fun.m"}]];
];

then modify the fun.m function to be

Function[ x, 
    x^2
]

This ensures that x is scoped correctly regardless of context.

$\endgroup$
2
  • $\begingroup$ Thanks a lot Jason! I'll try this as soon as I get access to my computer. 😉 $\endgroup$ Commented Jan 4, 2018 at 15:46
  • $\begingroup$ Using Function[{x}, ...] inside fun.m everything works! Again thanks a lot @JasonB. $\endgroup$ Commented Jan 4, 2018 at 20:51

Your Answer

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

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