Take the 2-minute tour ×
Mathematica Stack Exchange is a question and answer site for users of Mathematica. It's 100% free, no registration required.

How can you introduce a package, so that it is listed in $Packages, without adding it to $ContextPath?

Note that this question is concerned with defining a package when evaluating code, e.g. through evaluating a cell, rather than loading a package from a file.

This is useful if you want to add capabilities without introducing new "bare" symbols in any way -- they live in their own context and must be referenced through an explicit context, unless the user adds that context back to the context path.

share|improve this question
    
Do I understand correctly that you cannot use the equivalent of Block[{$ContextPath}, Needs["Combinatorica`"]] because the package is defined in a notebook, and it must be in multiple, separate input lines (therefore can't be wrapped)? BeginPackage affects parsing, so it takes effect only starting with the next input. –  Szabolcs Feb 4 '13 at 23:06
    
This seems to work even if you were to define the package and not load it (basically what Szabolcs said) –  rm -rf Feb 4 '13 at 23:19
1  
@rm-rf Nope, that can't be used if you define the package in a cell. The reason is that as soon as you wrap the definition in Block, it becomes a single input that is parsed before BeginPackage is evaluated and changes the context. So while it may appear to work on first try, the package symbols will all be created in the Global context. –  Szabolcs Feb 4 '13 at 23:21
    
@Szabolcs Ah yes, you're right. –  rm -rf Feb 4 '13 at 23:22
    
Ref: stackoverflow.com/questions/7917550/… BTW I upvoted this because when one starts to think of alternative solutions, it'll become clear that Joel's solution is not as trivial to figure out as it looks. –  Szabolcs Feb 4 '13 at 23:22

3 Answers 3

up vote 5 down vote accepted

Just using DeleteCases seems to work too:

  BeginPackage["ChurchNumerals`"];
    ZERO::usage = "ZERO is the Church encoding of zero";
    ONE::usage = "ONE is the Church numeral encoding of the integer 1";
    TWO::usage = "TWO is the Church numeral encoding of the integer 2";
    Begin["`Private`"];
    ZERO = Function[f, Function[n, n]];
    ONE = Function[f, Function[n, f[n]]];
    TWO = Function[f, Function[n, f[f[n]]]];
    End[];
    EndPackage[];
    $ContextPath = DeleteCases[$ContextPath, "ChurchNumerals`"]
share|improve this answer
    
While I appreciate the other answers, this is direct and simple and seems most like "the answer". –  Joel Klein Feb 5 '13 at 18:34

One way to do this is by taking note of how EndPackage works -- by adding \$Context to \$ContextPath:

ChurchNumerals`Private`prevContext = Context[];
BeginPackage["ChurchNumerals`"];
  ZERO::usage = "ZERO is the Church numeral encoding of zero";
  ONE::usage = "ONE is the Church numeral encoding of the integer 1";
  TWO::usage = "TWO is the Church numeral encoding of the integer 2";
  Begin["`Private`"];
    ZERO = Function[f, Function[n, n]];
    ONE = Function[f, Function[n, f[n]]];
    TWO = Function[f, Function[n, f[f[n]]]];
  End[];
  $Context = ChurchNumerals`Private`prevContext;
EndPackage[];

Now the package is on $Packages but not $ContextPath, and is used qualified with the package name:

Map[#[Function[n, n + 1]][0] &, 
   {ChurchNumerals`ZERO, ChurchNumerals`ONE, ChurchNumerals`TWO}]
share|improve this answer
3  
I would use the variable to store the context path and restore it after EndPackage instead of the current context. Simpler for the cases where EndPackage also adds the dependency list (second argument of BeginPackage) –  Rojo Feb 4 '13 at 23:48
    
Yeah, that works too. In my case I'm bending over backward not to introduce anything into context path, so I didn't think of that case of the 2nd argument to BeginPackage. –  Joel Klein Feb 5 '13 at 4:04

There is a simpler way:

BeginPackage["ChurchNumerals`"];

ZERO::usage = "ZERO is the Church encoding of zero";
ONE::usage = "ONE is the Church numeral encoding of the integer 1";
TWO::usage = "TWO is the Church numeral encoding of the integer 2";

Begin["`Private`"];

ZERO = Function[f, Function[n, n]];
ONE = Function[f, Function[n, f[n]]];
TWO = Function[f, Function[n, f[f[n]]]];

End[];

Block[{$ContextPath}, EndPackage[]];

It is the EndPackage which is responsible for keeping the context on the $ContextPath, so you can just Block only it.

Note that putting a Block around the whole thing won't work in the FrontEnd, since only the top-level statements are parsed one by one in a cell - so in that case, the symbols would end up created in a wrong (Global`) context.

share|improve this answer
1  
I think there should not be different parsers. It is hard to figure out the difference, harder to program around them and even harder to try to teach this. –  Rolf Mertig Feb 5 '13 at 0:41
1  
Why does this work? I find it weird that a line like this Block[{$ContextPath}, EndPackage[]]; can change the $ContextPath. Big +1 of course, I'm learning something new –  Rojo Feb 5 '13 at 0:49
2  
@Rojo This Block does not change the $ContextPath, it prevents the EndPackage from changing it globally. It is EndPackage which attempts to change things here. Soon, I will run out of tricks to surprise you :-). –  Leonid Shifrin Feb 5 '13 at 0:53
1  
...but before running that line the $ContextPath is just {ChurchNumerals`,System`}, and afterwards it goes back to having Global` and the rest –  Rojo Feb 5 '13 at 0:56
1  
I wouldn't have guessed, confusing. Even if it were true that you run out of tricks, we've come a long way –  Rojo Feb 5 '13 at 1:45

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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