5

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.

  • 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 – Jason B. Jan 03 '18 at 20:10
  • Hi Jason! You're right, the output shows that they are not in the same context: test\Private`f[test`Private`x_]=x^2`. – Giovanni Bordiga Jan 03 '18 at 20:32
  • 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. – Jason B. Jan 03 '18 at 20:34
  • 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. – b3m2a1 Jan 03 '18 at 20:48
  • @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. – Giovanni Bordiga Jan 03 '18 at 21:52
  • Hi @JasonB.! I tried the quick fix on the "test code" and it worked. Unfortunately I can't say the same for my code, even though they are conceptually the same to my eyes. In my code the output of ??test\Private`fshows the parameterx$instead ofx`... – Giovanni Bordiga Jan 04 '18 at 09:16
  • What do we know about fun.m file? Is symbol representing "function variable" always "lexically present" in (last) expression in the file, or can it appear dynamically during evaluation of this expression? Are all occurrences of this symbol always written in short form, without any context? – jkuczm Jan 04 '18 at 14:08
  • @jkuczm thanks for your comment! For all intended purposes the fun.m file contains an expression in the variable x (actually a list) e.g. {Sin[x], Exp[x^2], Tan[x-Log[x]]}. So no context is specified for x, right? – Giovanni Bordiga Jan 04 '18 at 15:39

1 Answers1

4

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.

Jason B.
  • 68,381
  • 3
  • 139
  • 286