14
$\begingroup$

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.

$\endgroup$
8
  • $\begingroup$ 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. $\endgroup$
    – Szabolcs
    Commented Feb 4, 2013 at 23:06
  • $\begingroup$ This seems to work even if you were to define the package and not load it (basically what Szabolcs said) $\endgroup$
    – rm -rf
    Commented Feb 4, 2013 at 23:19
  • 1
    $\begingroup$ @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. $\endgroup$
    – Szabolcs
    Commented Feb 4, 2013 at 23:21
  • $\begingroup$ @Szabolcs Ah yes, you're right. $\endgroup$
    – rm -rf
    Commented Feb 4, 2013 at 23:22
  • $\begingroup$ 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. $\endgroup$
    – Szabolcs
    Commented Feb 4, 2013 at 23:22

3 Answers 3

12
$\begingroup$

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`"]
$\endgroup$
1
  • $\begingroup$ While I appreciate the other answers, this is direct and simple and seems most like "the answer". $\endgroup$
    – Joel Klein
    Commented Feb 5, 2013 at 18:34
15
$\begingroup$

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.

$\endgroup$
16
  • 1
    $\begingroup$ 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. $\endgroup$ Commented Feb 5, 2013 at 0:41
  • 1
    $\begingroup$ 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 $\endgroup$
    – Rojo
    Commented Feb 5, 2013 at 0:49
  • 2
    $\begingroup$ @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 :-). $\endgroup$ Commented Feb 5, 2013 at 0:53
  • 1
    $\begingroup$ ...but before running that line the $ContextPath is just {ChurchNumerals`,System`}, and afterwards it goes back to having Global` and the rest $\endgroup$
    – Rojo
    Commented Feb 5, 2013 at 0:56
  • 1
    $\begingroup$ I wouldn't have guessed, confusing. Even if it were true that you run out of tricks, we've come a long way $\endgroup$
    – Rojo
    Commented Feb 5, 2013 at 1:45
5
$\begingroup$

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}]
$\endgroup$
2
  • 3
    $\begingroup$ 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) $\endgroup$
    – Rojo
    Commented Feb 4, 2013 at 23:48
  • $\begingroup$ 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. $\endgroup$
    – Joel Klein
    Commented Feb 5, 2013 at 4:04

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.