Определить частную функцию в пакете Mathematica

Я не уверен, что понял, как правильно определять частные функции. Когда я пишу пакет Mathematica, я просто делаю это:

BeginPackage["myPackage`"]
myPublicFunction::usage="myPublicFunction blahblahblah";
Begin["Private"]
myPrivateFunction[input_]:= ... ;
myPublicFunction[input_]:= ... ;
End[]
EndPackage[]

Это правильный путь или я что-то упустил?

1 ответ

Решение

Да, это правильный путь. Это может окупиться, чтобы понять некоторые внутренние механизмы пакета. Контексты Mathematica похожи на пространства имен в других языках. Они могут быть вложенными. Каждый символ принадлежит некоторому контексту. В любой момент некоторый контекст является "текущим". Всякий раз, когда создается новый символ, система должна решить, к какому контексту будет принадлежать символ. Это происходит в разбор времени. Основная величина (переменная) здесь $ContextPath, Это в основном путь поиска символов. Это список контекстов, и всякий раз, когда система видит новый символ, она проверяет, существует ли символ с таким же коротким именем (то есть именем самого символа без контекста) в некотором контексте на $ContextPath, Если он существует, то данное вхождение символа будет связано с существующим. Если это не так, то символ создается в текущем контексте. Обратите внимание, что это динамическая вещь - если вы измените $ContextPath в любой момент следующее вхождение символа может быть связано с другим символом.

В любом случае, что BeginPackage делает то, что он просто заменяет текущее значение $ContextPath просто {youPublicPackageContext, "System'"}плюс, возможно, дополнительные контексты, которые вы публично импортируете через второй необязательный аргумент BeginPackage, Поэтому все символы, которые находятся в разделе "public", анализируются в общедоступном контексте, если они не находятся в "System" или других контекстах, которые вы импортируете. И что EndPackage делает, чтобы восстановить значение $ContextPath до того, что было до того, как вы начали загружать пакет. Таким образом, технически сообщение об использовании не является единственным способом сделать символ общедоступным в вашем основном контексте - вы можете просто ввести символ с точкой с запятой, например myFunction; (эта практика не рекомендуется, я только что упомянул ее, чтобы прояснить механизм). Теперь, что происходит, когда вы входите Begin["'Private'"] является то, что текущий контекст становится YourContext'Private' (под-контекст). $ContextPath не изменился. Поэтому любой введенный символ, которого нет в вашем общедоступном пакете или других импортированных пакетах (то есть контексты, которые в настоящее время находятся в $ContextPath), автоматически разбирается в 'Private' подконтекст.

Что действительно делает эти символы закрытыми, так это то, что всякий раз, когда вы импортируете свой пакет в какой-то другой контекст (пакет), в него добавляется только основной пакет. $ContextPath, но не его подпакеты. Технически, вы можете нарушить инкапсуляцию, добавив вручную YourPackage'Private' в $ContextPath (скажем, PrependTo[$ContextPath, YourPackage'Private']), и тогда все ваши личные функции и другие символы станут общедоступными в том конкретном контексте, в котором вы выполняете импорт. Опять же, эта практика не рекомендуется, но она объясняет механику. Суть в том, что понятие частного или публичного может быть полностью понято, когда мы знаем, как анализируются символы, и каковы манипуляции с $ContextPath а также $Context (другая системная переменная, задающая значение текущего контекста), которые выполняются такими командами, как Begin а также BeginPackage, Иными словами, в принципе можно подражать действиям BeginPackage,Begin, End а также EndPackage с пользовательским кодом. Здесь действуют всего несколько принципов (которые я попытался обрисовать выше), и сам механизм на самом деле очень открыт для пользователя, так что если в некоторых редких случаях кому-то может понадобиться другое поведение, можно некоторые "нестандартные" манипуляции с $ContextPath а также Context, чтобы обеспечить какой-то нестандартный способ синтаксического анализа символов и, следовательно, контролировать инкапсуляцию в масштабе пакета некоторым "нестандартным" способом. Я не поощряю это, просто упомяну, чтобы подчеркнуть, что механизм на самом деле намного проще и гораздо более управляем, чем может показаться на первый взгляд.

Другие вопросы по тегам