Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

KDP_book

.pdf
Скачиваний:
19
Добавлен:
03.01.2021
Размер:
2.46 Mб
Скачать

Mathematica: Functional and procedural programming

The question of determining the formal arguments of user function is of quite certain interest. Built-in tools of the system do not directly solve this issue and we have created a number of tools for the purpose of determining the formal arguments of the function, module and block. For a function, this problem is solved e.g. by the ArgsF function with program code:

In[47]:= ArgsF[x_] := If[PureFuncQ[x], ArgsPureFunc[x],

If[FunctionQ[x], Args[x], ToString1[x]<>" not function"]] In[48]:= GS@Sequences[a_Integer, b_Symbol, c_] := a+b+c In[49]:= ArgsF[GS]

Out[49]= {a_Integer, b_Symbol, c_} In[50]:= H := #1^2 + #2^2*#3^4 & In[51]:= ArgsF[H]

Out[51]= {"#1", "#2", "#3"}

In[52]:= T := Function[{x, y, z}, x + y + z]; ArgsF[T]

Out[52]= {"x", "y", "z"}

In[53]:= ArgsF[Agn]

Out[53]= "Agn not function"

The call ArgsF[x] returns the list of formal arguments in the string format of function x, including pure function, if x is not a function the call returns the corresponding message. The ArgsF function uses the testing tools FunctionQ and PureFuncQ along with tools Args, ArgsPureFunc, and ToString1 with which it is possible to get acquainted in [1-12], while the interested reader can get acquainted here with a number of tools (that complement the built-in system tools) for work with the user functions.

For converting of a pure function of formats (a) and (b) to format (c) the PureFuncToShort procedure with the following program code serves:

In[4220]:= PureFuncToShort[x_ /; PureFuncQ[x]] :=

Module[{a, b, c, d},

If[ShortPureFuncQ[x], x, a = ArgsPureFunc[x]; d = a; b = Map[ToExpression, a]; Map[ClearAll, a]; a = Map[ToExpression, a]; c = Quiet[GenRules[a, Range2[#, Length[a]]]];

{ToExpression[ToString1[ReplaceAll[x[[2]], c]] <> "&"],

21

V.Z. Aladjev, M.L. Shishakov, V.A. Vaganov

ToExpression[ToString[d] <> "=" <> ToString1[b]]}[[1]]]]

In[4221]:= G := Function[{x, y, z}, p*(x + y + z)];

In[4222]:= PureFuncToShort[G]

Out[4222]= p*(#1 + #2 + #3) &

The procedure call PureFuncToShort[w] returns the result of converting of a pure function w to its short format. In turn, the PureFuncToFunction procedure is intended for converting of a pure function to classical. The following example presents its program code with a simple example of its application:

In[7]:= PureFuncToFunction[x_/; PureFuncQ[x], y_/; !HowAct[y]]:= Module[{a = ArgsPureFunc[x], b, c},

If[ShortPureFuncQ[x], b = (StringReplace[#1, "#" > "x"] &) /@ a; c = StringReplace[ToString1[x], GenRules[a, b]]; b = ToExpression /@ Sort[(#1 <> "_" &) /@ b];

ToExpression[ToString1[y[Sequences[b]]] <> ":=" <> StringTake[c, {1, 3}]], a = (#1 <> "_" &) /@ a;

ToExpression[ToString1[y[Sequences[ToExpression /@ a]]] <> ":=" <> ToString1[x[[2]]]]]]

In[8]:= t := p*(#1^2 + #2^2*#3^n) & In[9]:= PureFuncToFunction[t, H] In[10]:= Definition[H]

Out[10]= H[x1_, x2_, x3_] := p*(x1^2 + x2^2*x3^n)

The procedure call with two arguments x and H, where x – a pure function and H – an undefined symbol, converts the pure x function to a classical function named H.

We have programmed a number of procedures that ensure the mutual conversion of classical, pure and pure functions of the short format. In particular, the CfToPure procedure allows the classical functions to be converted into pure functions of the short format [12-16]. Calling the CfToPure[f] procedure returns the result of converting a classical function f to its equivalent in the form of a pure function of short format. The procedure uses a number of techniques useful in practical programming, which are recommended to the reader. The fragment below represents source code of the CfToPure procedure and examples of its use.

In[4]:= {x, y, z} = {42, 47, 67};

22

Mathematica: Functional and procedural programming

In[5]:= F[x_Integer, y_, z_ /; IntegerQ[z]] := (x^2 + y^3) + (y^2 x*y*z)/Sqrt[x^2 + y^2 + z^2] In[6]:= CfToPure[f_ /; FunctionQ[f]] := Module[{a, b, c, d}, a = Map[ToString[#] <> "@" &, Args[f]];

a = Map[StringReplace[#, "_" ~~ ___ ~~ "@" > ""] &, a]; d = "###"; Save2[d, a]; b = Map["#" <> ToString[#] &, Range[Length[a]]];

Map[Clear, a]; c = GenRules[a, b]; c = Map[ToExpression[#[[1]]] > ToExpression[#[[2]]] &, c]; a = StringReplace[Definition2[f][[1]], Headings[f][[2]] <> " := " > ""]; a = ToExpression[a <> " &"]; {ReplaceAll[c][a], Get[d], DeleteFile[d]}[[1]]]

In[7]:= CfToPure[F]

Out[7]= (x^2 + y^3) + (y^2 x*y*z)/Sqrt[x^2 + y^2 + z^2] & In[8]:= {x, y, z}

Out[8]= {42, 47, 67}

In[9]:= G[x_Integer, y_List, z_ /; IntegerQ[z]] := N[Sin[x]/ Log[Length[y]] + (y^2 – x*y*z)^(x+z)/Sqrt[x^2+y^2+z^2]] In[10]:= CfToPure[G]

Out[10]= N[Sin[#1]/Log[Length[#2]] + (#2^2 – #1*#2*#3)^ (#1 + #3)/Sqrt[#1^2 + #2^2 + #3^2]] &

As in a function body along with formal arguments global variables and calls of functions can enter, then the problem of determination them is of a certain interest to any function. In this regard the GlobalsInFunc function can be useful enough with the following program code:

In[2223]:= VarsInFunc[x_] := Complement[Select[VarsInExpr[

ToString2[Definition[x]]], ! SystemQ[#] &], {ToString[x]}, ArgsBFM[x]];

GlobalsInFunc[x_] := If[PureFuncQ[x], Complement[VarsInExpr[x], Flatten[{ArgsPureFunc[x],

"Function"}]], If[FunctionQ[x], VarsInFunc[x],

"Argument not function"]]

In[2224]:= F[x_, y_, z_] := a*x*b*y + N[Sin[2020]] In[2225]:= GlobalsInFunc[F]

Out[2225]= {"a", "b"}

23

V.Z. Aladjev, M.L. Shishakov, V.A. Vaganov

In[2226]:= G := Function[{x, y, z}, p*(x + y + z)];

In[2227]:= GlobalsInFunc[G]

Out[2227]= {"p"}

In[2228]:= T := p*(#1^2 + #2^2*#3^n) &

In[2229]:= GlobalsInFunc[T]

Out[2229]= {"n", "p"}

The call GlobalsInFunc[x] returns the list of global symbols in string format entering a function x definition (pure or classical) and other than the built-in symbols of Mathematica, if x is not a function, than the call returns the corresponding message. The function uses the tools of our MathToolBox package [7,8,16], in particular the function whose call VarsInFunc[x] returns the list of global symbols in string format entering a classical function x definition and other than the built-in symbols of the system.

Generally, the user functions do not allow to use the local variables, however a simple artificial reception allows to do it. Sequential list structure of execution of operations when the list is evaluated elementwise from left to right is for this purpose used, i.e. function is represented in the following format:

Name[args] := {Save["#", {locals}], {locals = values}, function body, Get["#"], DeleteFile["#"]}[[3]]

The presented format is rather transparent and well illustrates essence of the method of use in user function of local variables. The following simple example illustrates told:

In[9]:= GS[x_, y_, z_] := {Save["#", {a, b, c}], {a=2, b=7, c=6}, a*x + b + y + c*z, Get["#"], DeleteFile["#"]}[[3]]

In[10]:= {a, b, c} = {1, 2, 3} Out[10]= {1, 2, 3} In[11]:= GS[42, 47, 67]

Out[11]= 540 In[12]:= {a, b, c} Out[12]= {1, 2, 3}

In some cases, the given approach may prove to be quite useful in practical programming. A number of our software tools have effectively used this approach.

24

Mathematica: Functional and procedural programming

Meanwhile, a rather significant remark needs to be made regarding the objects multiplicity of definitions with the same name. As noted repeatedly, Mathematica system differentiates objects, above all, by their headers, if any. It is therefore quite real that we may deal with different definitions under the same name. This applies to all objects that have headers. In view of this circumstance, we have programmed a number of tools for various cases of application [1-16]. First of all, we need a tool of testing the presence of such multiplicity for a particular object (function, module, block). This function is successfully performed by the MultipleQ procedure with program code:

In[47]:= MultipleQ[x_ /; SymbolQ[x], j___] := Module[{a}, a = ToString[InputForm[Definition[x]]];

a = StringReplace[a, "\n \n" → "\[CircleDot]"]; a = StringSplit[a, "\[CircleDot]"]; If[{j} != {} && !ValueQ[j], j=a]; If[Length[a] > 1, True, False]]

In[48]:= G[x_, y_] := p*(x^2 + y^2); G[x_Integer, y_] := x*y

G[x_, y_, z_] := x^2 + y^2 + z^2; G[x_, y_List] := x*y In[49]:= MultipleQ[G, gs]

Out[49]= True In[50]:= gs

Out[50]= {"G[x_Integer, y_] := x*y", "G[x_, y_List] := x*y", "G[x_, y_] := p*(x^2+y^2)", "G[x_, y_, z_] := x^2+y^2+z^2"}

In[53]:= MultipleQ1[x_ /; SymbolQ[x], j___] :=

Module[{a = Definition2[x]}, If[{j} != {} && ! HowAct[j], j = a[[1 ;; –2]], 77];

If[Length[a[[1 ;; –2]]] == 1, False, True]] In[54]:= MultipleQ2[x_Symbol] := If[Length[ToExpression[

Unique1[Definition2[x], j]][[1 ;; –2]]] > 1, True, False]

The call MultipleQ[x] returns True if symbol x has multiple definitions, and False otherwise. Through optional j argument the list of x definitions in string format is returned. MultipleQ1 and MultipleQ2 tools functional analogues of the MultipleQ.

At last, quite natural interest represents the existence of the user procedures and functions activated in the current session. Solution of the question can be received by tool of a procedure whose call ActBFMuserQ[] returns True if such objects exist in

25

V.Z. Aladjev, M.L. Shishakov, V.A. Vaganov

the current session, and False otherwise; the call ActBFMuserQ[x] thru optional x argument an indefinite variable returns the 2– element nested list whose the first element contains name of the user object in the string format while the second defines list of its types in string format respectively. The fragment represents source code of the ActBFMuserQ with an example of its use.

In[7]:= ActBFMuserQ[x___ /; If[{x} == {}, True, If[Length[{x}] == 1

&& ! HowAct[x], True, False]]] := Module[{b = {}, c = 1, d, h, a = Select[Names["`*"], ! UnevaluatedQ[Definition2, #] &]},

For[c, c <= Length[a], c++, h = Quiet[ProcFuncTypeQ[a[[c]]]]; If[h[[1]], AppendTo[b, {a[[c]], h[[1]]}], Null]]; If[b == {}, False, If[{x} != {}, x = ReduceLists[b]]; True]]

In[8]:= V := Compile[{{x, _Real}, {y, _Real}}, (x^3 + y)^2]; Art := Function[{x, y}, x*Sin[y]]; K := (#1^2 + #2^4) &;

GS[x_ /; IntegerQ[x], y_ /; IntegerQ[y]] := Sin[90] + Cos[42]; G = Compile[{{x, _Integer}, {y, _Real}}, x*y];

H[x_] := Block[{}, x]; H[x_, y_] := x + y; SetAttributes["H", Protected]; P[x_] := Module[{}, x]; P[y_] := Module[{}, y]; P[x__] := Plus[Sequences[{x}]]; T42[x_, y_, z_] := x*y*z; R[x_] := Module[{a = 590}, x*a];

GSV := (#1^2 + #2^4 + #3^6) & In[9]:= ActBFMuserQ[]

Out[9]= True

In[10]:= {ActBFMuserQ[t77], t77} Out[10]= {True, {{"Art", {"PureFunction"}},

{"G", {"CompiledFunction"}}, {"GS", {"Function"}}, {"H", {"Block", "Function"}}, {"P1", {"Function"}}, {"R", {"Module"}}, {"K", "ShortPureFunction"}, {"V", {"CompiledFunction"}},

{"P", {"Module", "Module", "Function"}, {"T42", {"Function"}}, {"GSV", "ShortPureFunction"}}}}

The ActBFMuserQ procedure is of interest as an useful tool first of all in the system programming.

Along with the presented tools a number of other useful tools for working with user functions and instructive examples of their application can be found in [1-16]. Here again it should be noted that the examples of tools presented in this book use

26

Mathematica: Functional and procedural programming

the tools of the mentioned MathToolBox package [16] that has freeware license. Given that this package and its tools will be frequently mentioned below, we will briefly describe it.

The package contains more than 1420 tools which eliminate restrictions of a number of the standard Mathematica tools and expand its software with new tools. In this context, the package can serve as a certain additional tool of modular programming, especially useful in numerous applications where certain non– standard evaluations have to accompany programming. At the same time, tools presented in the package have the most direct relation to certain principal questions of procedurefunctional programming in Mathematica, not only for decision of applied tasks, but, above all, for programming of software extending frequently used facilities of the system and/or eliminating their defects or extending the system with new facilities. Software presented in this package contains a number of useful enough and effective receptions of programming in Mathematica, and extends its software which allows in the system to programme the tasks of various purposes more simply and effectively. The additional tools composing the above package embrace a rather wide circle of sections of the Mathematica system [15,16].

The given package contains definitions of some functionally equivalent tools programmed in various ways useful for use in practical programming. Along with this, they illustrate a lot of both efficient and undocumented features of Math-language of the system. In our opinion, the detailed analysis of source code of the package software can be a rather effective remedy on the path of the deeper mastering of programming in Mathematica. Experience of holding of the master classes of various levels on the systems Mathematica and Maple in all evidence confirms expediency of joint use of both standard tools of the systems of computer mathematics, and the user tools created in the course of programming of various appendices. A lot of tools contained in the package and mentioned below were described in [1-15] in detail enough. We now turn to the procedural objects of the

Mathematica system.

27

V.Z. Aladjev, M.L. Shishakov, V.A. Vaganov

Chapter 2: The user procedures in Mathematica

Procedure is one of basic concepts of programming system of Mathematica, being not less important object in systems of programming as a whole. A procedure is an object implementing the well-known concept of "black box" when with known input

(actual arguments) and output (returned result) while the internal structure of the object, generally speaking, is closed. Procedure forms the basis of the so-called "procedural programming" where in the future by the procedure we will understand such objects as module and block. Procedural programming is one of basic paradigms of Mathematica which in an essential degree differs from similar paradigm of the well-known traditional procedural programming languages. This circumstance is the cornerstone of certain system problems relating to procedural programming in Mathematica. Above all, similar problems arise in the field of distinctions in implementation of the above paradigms in the Mathematica and in the environment of traditional procedural languages. Along with that, unlike a number of traditional and built-in languages the built-in Math–language has no a number of useful enough tools for operating with procedural objects. In our books [1-15] and MathToolBox package [16] are presented some such tools.

A number of the problems connected with similar tools is considered in the present chapter with preliminary discussion of the concept of `procedure` in Mathematica system as bases of its procedural paradigm. In addition, tools of analysis of this section concern only the user procedures and functions because definitions of all builtin system functions (unlike, say, from the Maple system) from the user are hidden, i.e. are inaccessible for processing by the standard tools of Mathematica system. Note that the discussion of procedural objects will take place relative to the latest version of Mathematica 12.1, which can dissonance with Mathematica of earlier versions. However this should not cause any serious misunderstandings. Math-language possesses a rather high level of immutability in relation to its versions.

28

Mathematica: Functional and procedural programming

2.1. Definition of procedures in Mathematica software

Procedures in Mathematica system are formally represented by program objects of the following 2 simple formats, namely:

M[x_ /; Testx, y_ /; Testy, ...] {:= | =} Module[{locals}, Module Body]

B[x_ /; Testx, y_ /; Testy, ...] {:= | =} Block[{locals}, Block Body]

i.e., procedures of both types represent the functions from two arguments the procedure body (Body) and local variables (locals). Local variables the list of names, perhaps, with initial values which are attributed to them. These variables have the local character concerning the procedure, i.e. their values aren't crossed with values of the symbols of the same name outside of the procedure. All other variables in the procedure have global character, sharing field of variables of the Mathematica current session. In addition, in the procedure definition it is possible to distinguish six following component, namely:

procedure name (M and B in the both procedures definitions);

procedure heading ({M|B}[x_ /; Testx, y_ /; Testy, ...] in the both

procedures definitions);

procedural brackets (Module[] and Block[]);

local variables (list of local variables {locals}; can be empty list);

procedure (Module, Block) body; can be empty;

testing Testx function (the function call Test[x] returns True or

False depend on permissibility of an actual x argument; can absent).

When programmed, we typically try to program tasks as modular programs as possible to make them more readable and independent, and more convenient to maintain. One of ways of a solution of the given problem is use of the scope mechanism for variables, defining for them separate scopes. Mathematica provides 2 basic mechanisms for limiting the scope of variables in form of modules and blocks, hereinafter referred to as general term – procedures. Procedures along with functions play a decisive role in solving the issue of optimal organization of program code. Note, real programming uses modules much more frequently, but blocks are often more convenient in interactive programming.

29

V.Z. Aladjev, M.L. Shishakov, V.A. Vaganov

Most traditional programming languages use a socalled "lexical scoping" mechanism for variables, which is analogous to the mechanism of modules in Mathematica. Whereas symbolic programming languages e.g. LISP allow also "dynamic scoping", analogous to the mechanism used by blocks in Mathematica. When lexical scoping is used, variables are treated as local ones to a particular part of a program code. At a dynamic scoping, the values of the allocated variables are local only to a certain part of the program execution. A Module carries out processing of the body when it is carried out as a component of the general program code, any variable from locals in the module body is considered as local one. Then natural execution of the general program code continues. A Block, ignoring all expressions of a body, uses for it the current values of variables from locals. In the course of execution of body the block uses values of locals for variables then recovers their original values after completion of the body. Most vividly these differences an example illustrates:

In[2254]:= {b, c} = {m, n};

In[2255]:= B[x_] := Block[{a = 7, b, c}, x*(a + b + c)]; B[7]

Out[2255]= 7*(7 + m + n) In[2256]:= {b, c} Out[2256]= {m, n}

In[2257]:= LocVars[x_String] := ToExpression[x <> "$" <>

ToString[$ModuleNumber 4]] In[2258]:= M[x_] := Module[{a = 7, b, c}, x*(a + b + c)]; M[7]

Out[2258]= 7*(7 + b$21248 + c$21248)

In[2259]:= Map[LocVars, {"a", "b", "c"}]

Out[2259]= {a$21248, b$21248, c$21248}

Thus, Module is a scoping construct that implements lexical scoping, while Block is a scoping construct implements dynamic scoping of local variables. Module creates new symbols to name each of its local variables every time it is called. Call of LocVars function immediately after calling a module (not containing calls of other modules) with local variables {a, b, c,...} returns the list of variables Map[LocVars, {"a","b","c",...}] that were generated at the time the module was called.

30

Соседние файлы в предмете Математические пакеты