• 七、程序包



    七、程序包                      返回目录页

    1、运行目录与规则库目录
    2、目录和符号
    3、搜索顺序
    4、载入程序包
    5、自制程序包
    6、标准程序包


    表达式的计算过程,是个递归的过程:
    一边在规则库中搜索规则(rule),一边进行变换(transformation),直到无规则可用为止。

    -------------------------------------------------------------------------
    1、运行目录与规则库目录
    当我们打开或新建一个笔记本文件,输入代码,然后运行。表面上看起来很简单。
    但是呢,背后隐藏着太多的东西。
    前面第四章,我们讲了表达式的运算过程,然后总结出,MMA的核心编程思想是:规则编程。
    规则编程这套系统具体是怎么构建的呢?规则库在什么地方呢?
    如果先浏览一下这一章,再去看第四章,可能更容易明白。

    ----------------------------------------
    运行目录。
    在同一个笔记本文件中,我们可以在不同的运行目录下编程。

    Begin["A`"]
    $Context
    End[]
    $Context
    得:Global`

    Begin["A`"]  新建目录A,并进入了目录A
    $Context 是个全局变量,返回MMA进程中的当前运行目录名
    End[]  退出目录A,返回进入目录A之前那个目录

    ` 是倒引号或重音符字符(ASCII 码是 96),在这里是运行目录标志。
    Global` 是全局运行目录,一开始打开或新建笔记本文件时,这个运行目录就自动打开。

    A`x="textA"
    B`x="textB"
    Global`x="textGlobal"
    x
    三个变量x,分别在不同目录下,它们的值都不同。
    如果用全名,可以像用一般其它符号一样使用它们。
    如果变量多时,给变量分类很方便,分别放在A、B...目录。当变量名相同时,也不会冲突。
    如果每次用全名,比较麻烦,所以我们经常不用全名,而直接写变量:Global`x与x,返回同一值。

    ----------------------------------------
    规则库目录

    当我们输入:Global`x="textGlobal" 时,定义了一个规则,在运行目录下,建立了一个变量x,值是"textGlobal"。
    那这个规则,保存在什么地方呢?即规则库在什么地方呢?
    答案是:也是保存在Global`目录中。

    所以对于Global`目录来说,既是运行目录,又是变换规则库目录
    在帮助文档中,翻译成了上下文(context),看起来非常别扭。我们在这里,称之为运行目录,或者规则库目录,有时简称为目录,比较好理解。


    -------------------------------------------------------------------------
    2、目录和符号
    运行目录与操作系统中的文件目录,在结构上是很像的,都是树形结构。
    文件目录下,可以有文件目录与文件。
    一样地,运行目录下,可以有运行目录与符号(定义、变量、规则,名称很多,指的是同一东西)。
    一些文件操作的概念也很相似,无非在MMA中,以函数的形式来操作。

    $Context
    Context[]
    都是返回当前目录名。

    Context[x]
    返回一个符号的目录。

    Clear[x]
    x
    清除一个符号的值

    Remove[x]
    ?x
    从系统中完全删除一个符号


    ++++++++++++++++++++++++++++++++++++++++++++++++++++++
    Clear["form"]    删除名与 form 匹配的所有符号的值
    Clear["context`*"]    删除在指定目录中所有符号的值
    Remove["form"]    完全删除名称与 form 匹配的符号
    Remove["context`*"]    在指定的目录中删除所有符号
    如:
    xx = 3;
    xx
    Clear["x*"];
    xx

    xx = 3;
    x = 2;
    Clear["Global`x*"];
    xx
    x

    xx = 3;
    xx
    Remove["x*"];
    ?xx

    xx = 3;
    x = 2;
    Remove["Global`x*"];
    ?xx
    ?x
    ++++++++++++++++++++++++++++++++++++++++++++++++++++++

    Names["form"]    给出与 form 匹配的符号列表
    如:
    xx = 3;
    x = 2;
    Names["x*"]
    Names["System`Ab*"]

    NameQ["form"]    测试是否有与 form 匹配的已存在符号
    如:
    NameQ["System`Ab*"]
    NameQ["System`AB*"]
    (* 前两句很好用,可以检查符号有木有用过 *)


    Contexts[]    所有目录组成的集合
    Contexts[]

    Contexts["string"]  给出匹配字符串的目录列表
    Contexts["A*"]


    -------------------------------------------------------------------------
    3、搜索顺序
    运行目录与规则目录,都是按树形结构安排的。这点已经清楚了。
    那么当程序运行时,要找规则来匹配。规则目录有很多,按什么顺序来搜索规则呢?
    有一个全局变量:
    $ContextPath
    用来决定目录的搜索顺序。
    返回可搜目录的列表。这个列表中,目录是按一定顺序排列的。

    那什么叫“一定顺序”?
    当文件刚建立时,有个默认的顺序:
    $ContextPath
    得:{..., "System`", "Global`"}
    目录"System`" 在目录 "Global`" 之前,意味着先搜索"System`"目录,再搜索"Global`"目录。
    ("System`"目录中,存放着所有内置函数。)

    那在$ContextPath中的各个目录中,还是搜索不到,咋办?
    那就搜索当前的工作目录($Context)。当前的工作目录,就是当前的规则库目录。

    那还是木有,咋办?
    那就好办了,工作完毕,表达式计算完毕,原样输出。

    规则总的搜索顺序就是:MMA总是先搜索$ContextPath列表中的规则库目录,再搜索当前的工作目录。

    ----------------------------------------
    关于搜索顺序的讨论。
    以上总的搜索顺序是说明文档中说的。而在一本非常好的入门书的两个版本中,说法却均与之相反。
    (
    《数学软件Mathematica入门》第一版的中文版。
    An Introduction To Programming With Mathematica 3Ed
    )
    到底谁对谁错?

    ----------------------------------------
    最好的办法是实验验证。在验证之前,要说个事。

    $ContextPath作为全局变量,是可以任意修改的。这意味着,MMA完全允许用户自定义搜索顺序。

    (****************
    $ContextPath = {}
    1+2
    *****************)

    这是个破坏性实验,所有规则库报废,1+2是算不出来了。
    而且无法恢复,因为这个笔记本文件已经丧失一切计算功能(无任何规则可以匹配)。
    那再新建一个笔记本文件好了?还是不行。
    只能重启MMA了。
    严重警告,在做这个实验前,把前面工作保存好!

    还好,重启MMA正常了。下面开始做正常试验:
    A`x = "textA";
    B`x = "textB";
    Global`x = "textGlobal";
    $ContextPath = {"B`", "A`", "System`", "Global`"};
    x
    Begin["A`"];
    x
    End[];
    $ContextPath = {"A`", "B`", "System`", "Global`"};
    x
    Begin["A`"];
    $ContextPath = {"Global`", "A`", "B`", "System`"};
    x
    $ContextPath = {"Global`", "System`"};
    y = "textAy";
    y
    End[];
    y
    Context[y]

    观察结果,得出结论:
    “MMA总是先搜索$ContextPath列表中的规则库目录,再搜索当前的工作目录。”
    这句话是完全正确的,但不完整。完整的表述是:
    MMA总是先搜索$ContextPath列表中的规则库目录,再搜索当前的工作目录——如果还没找到,则搜索剩下的没有搜索过的工作目录。

    根据以上的搜索过程,得出计算过程:...如果找到,则马上进行替换,如果找不到,则原样输出。
    这只是完全匹配的情况。如果考虑到模式匹配,要在所有可能的匹配中,找到最匹配的。。
    MMA是个复杂的系统。

    -------------------------------------------------------------------------
    4、载入程序包
    在使用MMA编程中,很多时候,内置函数(共有3000个左右)已经够用。
    但在更多时候,当我们有更多的需求的时候,希望有更多的函数可用。
    每个MMA标准版,都包含了标准程序包。
    程序包(package)是函数的集合,即把函数们打包了。
    要使用程序包,必须要先载入。载入之后,在程序包中函数的使用上,与内置函数已经没有区别。
    如果标准程序包还不能满足用户的需求,用户可以自定义程序包。
    自定义程序包在使用时也一样要先载入。然后在使用上与内置函数也没有啥区别。
    所有程序包以外部文件的形式在操作系统的文件管理系统中存放,一般文件名为这种形式:package.m

    ----------------------------------------
    $Packages

    给出当前MMA进程中所加载的所有程序包对应的规则库列表。(包含Global`目录)
    一般来说,程序包对应的外部文件的文件名,与程序包内定义的规则库目录名称,保持统一。

    $ContextPath
    返回可搜规则目录的列表。前面已经使用过。

    $ContextPath可用户自定义,按需要改变内容。但$Packages
    是受到保护的,不可以改变。

    一般程序包加载成功,系统不会有任何提示。但加载不成功,则会有错误提示。
    加载成功意味着:
    A、程序包对应规则目录,已经添加到$Packages列表最前面。
    B、程序包对应规则目录,已经添加到$ContextPath列表最前面。

    Needs["ComputerArithmetic`"]
    $Packages
    $ContextPath

    ComputerArithmetic`是标准程序包之一,外部文件(ComputerArithmetic.m)存放目录:
    ...Mathematica9AddOnsPackagesComputerArithmetic

    加载成功后,可以用Names函数,来查看加载的程序包中有哪些函数可用:
    Names["ComputerArithmetic`*"]

    然后可以查询函数的功能。
    ?Arithmetic
    然后,还可以打开帮助文档。(点击右下角的 >> )


    ----------------------------------------

    加载程序包

    Needs["context`"] 调用 Get["context`"]。
    所以我们只要学习Get函数。
    << 是Get函数的语法糖。

    $Path
    给出在试图找到一个外部文件时搜索的缺省文件目录列表
    运行一下,看看输出。
    $Path表是可以修改的。但要注意,如果给它改成了空表,则再也无法载入外部文件了。

    Get函数,可以加载很多类型的外部文件。无一例外地,总是搜索每一个$Path表中的每个元素。
    我们在这里,只关心Get["context`"]这种类型的情况,即加载程序包文件context.m,得到context`规则库目录。

    具体说,Get["context`"]分两种情况:
    A、加载文件
    (潜规则是,想加载程序包con.m文件、得到con`规则库目录,把两者取同名:这里名字都是con。)
    Get["con`"]
    运行时,在所有$Path表中的每个元素(即文件路径)下,寻找con.m文件。一旦找到,就停止寻找,然后载入con.m文件。
    有时候,文件都不在这些搜索路径之下,可以这样写:
    Get["dir`con`"]
    那就是在搜索路径之下,寻找dir文件夹下的con.m文件。找到就停止寻找,然后载入。
    还有一种写法,与$Path表中路径无关,直接指定若干寻找目录,格式是:
    Get[name,Path->{dir1,dir2,...}]
    比如写成这样:
    Get["SayHi`", Path -> "X:/aaa"]
    即SayHi.m在X:/aaa/目录下,可以这样直接找到并载入。

    要注意的一个事是,目录作为一个字符串的形式表达
    "X:/aaa/"
    "X:\aaa\"
    这两种形式都可以,但不能写成:
    "X:aaa"
    因为类似于C语言中的字符串中,已经用于转义,请观察:
    "X: aa"
    得:
    "X:
    aa"
    作为一个整体,转换成了换行符。


    B、加载目录
    在$Path各路径下,搜索文件与搜索目录是同时进行的。
    当文件在$Path各路径下找不到时,找context目录。
    (这里又有个潜规则,想加载目录con,得到con`规则库目录,则把两者取同名:con)
    加载目录的过程是,当找到con目录时,在con目录下寻找Kernel目录中的init.m文件。然后运行init.m文件中的语句。(加载目录只是用于表达一种加载方法。目录无法加载,真实加载的还是文件,通过init.m中的语句。)
    哪怕init.m中一句语句也没有,MMA也会认为工作完毕,而停止寻找。
    如果找不到init.文件,则在con目录下找匹配的程序包文件来试图载入。
    标准程序包,都是以这种“加载目录”的形式载入的,都通过init.m文件。
    所以标准程序包对应的外部文件,都这样组织:
    con目录下,有若干程序包文件,然后还有一个文件夹Kernel,里面有个init.m文件。

    可以用FindFile函数,找到init.m文件的具体位置:
    Needs["ComputerArithmetic`"]
    FindFile["ComputerArithmetic`"]


    ----------------------------------------
    DeclarePackage
    DeclarePackage["context`",{"name1","name2", ...}]
    声明如果任何具有指定名称的符号被使用的话,则 Needs["context`"] 应该自动执行

    $ContextPath
    DeclarePackage["StatisticalPlots`", "ParetoPlot"]
    ParetoPlot[{a, b, c, d, d, d, e, d, e, e, f, a, b, c}]
    $ContextPath

    这也是载入程序包的一种方法。

    ----------------------------------------
    自动加载程序包

    假如一个SayHi.m,存放在X:aaa目录中时(操作系统为Win系列),想要MMA每次启动时,都自动加载,咋办?

    $BaseDirectory
    $UserBaseDirectory
    这两个文件夹中(以下操作,在这两个文件夹中的任一个,都可以),都有autoload文件夹与Kernel文件夹。

    Kernel文件夹中的init.m文件能够在mma启动的时候自动加载。
    用记事本打开init.m文件,如果没有,则创建一个init.m文件。
    添加下面内容:
    Get["SayHi`", Path -> "X:/aaa"]
    启动MMA:
    $Packages
    $ContextPath
    可以看到,SayHi`规则目录都在里面了。


    还有一种方法,是在autoload文件夹中做文章。
    在autoload文件夹下,建立一个子文件夹:SayHi
    然后再在SayHi文件夹下,建立一个子文件夹:Kernel。
    然后再在Kernel文件夹下,建立一个init.m文件。(只要先用记事本建立一个txt文件,然后改名就行)
    init.m文件中,只有一句话:
    Get["SayHi`SayHi`"]
    最后,把SayHi.m文件,从X:/aaa文件夹,copy到SayHi文件夹下。
    完工。
    启动MMA:
    $Packages
    $ContextPath
    可以看到,SayHi`规则目录都在里面了。
    ?SayHi`*
    可以看到里面的函数了。


    -------------------------------------------------------------------------
    5、自制程序包
    程序包可以自制。
    一方面,当程序比较大型的时候,自制程序包可以使代码容易维护,也更容易编写。
    另一方面,通过学习程序包的自制过程,可以更容易理解标准程序包。

    ----------------------------------------
    下面我们来制作自定义程序包:Say.m
    选择菜单:文件/新建/程序包。
    然后在弹出窗口中开始编辑文本。
    输入以下内容:

    $ContextPath
    BeginPackage["Say`"]
      $ContextPath
      Begin["`Private`"]
        $ContextPath
      End[ ]
      $ContextPath
    EndPackage[ ]
    $ContextPath
    然后保存程序包,假设保存为:X:/aaa/Say.m
    然后点击右上角的“运行程序包”,看下面的输出结果。

    这个程序,主要是为了观察$ContextPath的内容变化。
    BeginPackage["Say`"]  (* {"Say`", "System`"} *)
    EndPackage[]  (* 恢复到之前内容 *)
    这两句,改变了$ContextPath的内容。
    而Begin["`Private`"]不会改变$ContextPath的内容。

    结合第3节内容,我们马上了解了程序包的工作方式。

    ----------------------------------------
    再把内容修改为:

    (* ^ *)
    BeginPackage["Say`"]
      Say::usage = "这是Say程序包。"
      Begin["`Private`"]
        Say := Print["SayOut"]
        SayA:= Print["SayAOut"]
      End[ ]
      SayB:=Print["SayBOut"]
    EndPackage[ ]
    点击保存。然后再点击“运行程序包”

    注意三个地方的颜色。Say/SayA/SayB
    注意把下图所指的地方,设置成鲜艳的颜色。



    ----------------------------------------
    在笔记本文件中,输入:
    Get["Say`", Path -> "X:/aaa"]
    $Packages
    $ContextPath
    可以看到,Say程序包载入进来了。

    ?Say`*
    可以看到,Say::usage部分的提示信息出来了。

    Names["Say`*"]
    得:{"Say", "SayB"}

    Say
    SayA
    SayB
    可以看到,仅SayA没有被替换。
    因为SayA的定义,躲在
      Begin["`Private`"]
        SayA:= Print["SayAOut"]
      End[ ]
    之中,是外部不可见的。
    所以一些临时变量啊、局部变量啊,可以躲到这里面去。

    没有赋值的全局符号,可以用特殊颜色显示,这个非常好用,如图:


    ----------------------------------------
    前面不断用到的SayHi.m,就更简单了:

    X:/aaa/SayHi.m

    (* 22:35 2016-11-2 *)
    BeginPackage["SayHi`"]
      SayHi::usage = "这可是我的第一个程序包啊!"
      SayHi := Print["一定载入成功!"]
    EndPackage[ ]

    笔记本中:
    Get["SayHi`", Path -> "X:/aaa"]
    $Packages
    $ContextPath

    ?SayHi`*
    Names["SayHi`*"]
    SayHi

    一边打开程序包文件,进行改写。
    一边在笔记本文件中进行载入输出等调试。
    这是可以的,不用不断重启MMA。
    只是要注意多按“保存”、“更新”。
    最后强调一句:多观察字符的颜色很重要


    -------------------------------------------------------------------------
    6、标准程序包

    帮助文档中有标准程序包的详细说明:
    guide/StandardExtraPackages
    Mathematica 9.0 标准程序包
    只是没有翻译成中文。

    每个程序包,都可以去找到源代码,在以下目录中:
    ...Mathematica9AddOnsPackages
    内容非常丰富。


    +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

    MMA的基本入门内容介绍完毕,接下来做什么呢?

    要么去看帮助文档:函数浏览器。MMA的内置函数,有三千个左右,我们这里只介绍了一小部分。去看按功能分类的函数浏览器,可以扩大我们的函数量(如同学英语时扩大词汇量)。

    要么去看目录页中介绍的类似的书,去看MMA的应用代码。在应用中扩大函数量(用F1很方便啊)。

    +++++++++++++++++++++++++++++++

    扩展阅读:木有。有时间的话,去浏览一下标准程序包的代码

    对了,MMA老板,一个给整个世界建模的奇人,是如何介绍MMA的呢?
    看个视频吧。







                                T o p

     

  • 相关阅读:
    zkRollup原理(转载)
    2012元旦遭遇坑爹的12306订票网站付了款不出票
    VM.xPort.ExcelClient XXX备忘
    Parsing html markup text using MSHTML
    Asp.net中模仿Winform的MessageBox
    ReportViewer 2008 打印出现Error loading resource library. (0x8007007E)和(0x80070006)
    使用ADO.net将数据导出到Excel并提供下载
    【备忘】Oracle常用系统表(做代码生成器用得到)
    Worm.Sober.b(“清醒”病毒)
    发布基于T4模板引擎的代码生成器[Kalman Studio]
  • 原文地址:https://www.cnblogs.com/xin-le/p/6014425.html
Copyright © 2020-2023  润新知