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

KDP_book

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

Mathematica: Functional and procedural programming

that is especially important when debugging a rather large and complex software by transferring the local variables to the level of variables, unique for the current session. In certain cases this approach to debugging has quite certain advantages. For such purpose the simple LocalsInProc procedure which is based on the predetermined variable $ModuleNumber which determines the current serial number to be used for local variables that are created can appear quite useful. Any Mathematica session starts with $ModuleNumber set to 1, receiving the increment for each new local variable in the current session. The fragment below represents source code of the procedure with examples of use.

In[47]:= LocalsInProc[t_List] := Module[{a, b = Length[t]},

a = Map[ToString, ($ModuleNumber 5)*

Flatten[Tuples[{1}, b]]];

Map[t[[#]] <> "$" <> a[[#]] &, Range[b]]]

In[48]:= Agn2[x_] := Module[{a, b, c, d}, Print[{a, b, c, d}]; {a, b, c, d} = {42, 47, 67, 77}; x*a*b*c]

In[49]:= Agn2[77]

{a$13366, b$13366, c$13366, d$13366} Out[49]= 10183866

In[50]:= LocalsInProc[{"a", "b", "c", "d"}]

Out[50]= {a$13366, b$13366, c$13366, d$13366} In[51]:= Avz[x_] := Module[{a, b, c}, Print[{a, b, c}];

a[t_] := t^2; a[x]]; Avz[77]

{a$49432, b$49432, c$49432} Out[51]= 5929

In[52]:= LocalsInProc[{"a", "b", "c"}]

Out[52]= {"a$49432", "b$49432", "c$49432"}

The procedure call LocalsInProc[g] should follow directly a P procedure call, where g – the list of local variables of the P procedure, with return of the list of representations in form of x$nn (x – a variable name and nn – an integer in string format) that are generated for local variables of the P procedure. If g defines the empty list, i.e. procedure P has no local variables, then the call LocalsInProc[{}] returns the empty list, i.e. {}.

81

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

Additionally, a number of Locals ÷ Locals5 tools have been programmed, using some useful programming techniques and returning local variables in various sections. A typical example is the procedure whose call Locals5[x] returns the list of local variables in string format with initial values assigned to them, for a module, or a block x. While calling Locals5[x, y] with the second optional argument y – an undefined symbol through it additionally returns the list consisting of two-element sub-lists whose elements in string format represent local variables and initial values ascribed to them. If there are no local variables, the empty list is returned. The fragment below represents the source code of the procedure with examples of its application.

In[422]:= Locals5[x_ /; BlockModQ[x], y___] := Module[{a, b, c}, a = StringJoin[Insert[Reverse[Headings[x]], " := ", 2]] <> "["; b = StringReplace[PureDefinition[x], a –> "", 1]; Do[c = StringTake[b, k]; If[SyntaxQ[c], Return[c], 7], {k, StringLength[b]}]; If[c == "{}", c = {}, c = StrToList[StringTake[c, {2, –2}]]];

If[{y} == {}, c, If[SymbolQ[y], y = Map[StringSplit[#, " = "] &, c]; c, c]]]

In[423]:= M3[x_] := Block[{a = 90, b = 49, c, h}, h = 77; x*h]; B1[x_] := Block[{a = 90, b = 50, c = {72, 77}, d = 42}, x*a*b*c*d]; B[x_] := Block[{}, x]; Locals5[M3]

Out[423]= {"a = 90", "b = 49", "c", "h"} In[424]:= Locals5[B]

Out[424]= {} In[425]:= Locals5[B1]

Out[425]= {"a = 90", "b = 50", "c = {72, 77}", "d = 42"} In[426]:= Locals5[B1, agn]

Out[426]= {"a = 90", "b = 50", "c = {72, 77}", "d = 42"} In[427]:= agn

Out[427]= {{"a", "90"}, {"b", "50"}, {"c", "{72, 77}"}, {"d", "42"}} In[428]:= Locals5[B, vsv]; vsv

Out[428]= {}

In[429]:= Locals5[M3, art]; art

Out[429]= {{"a", "90"}, {"b", "49"}, {"c"}, {"h"}}

As an analogue of the above Locals5 procedure we present the Locals6 procedure which uses certain useful programming

82

Mathematica: Functional and procedural programming

technique of the strings. The procedure has analogous formal arguments and its call returns results analogous to the call of the above Locals5 procedure. The following fragment represents source code of the procedure with examples of its application.

In[3119]:= Locals6[x_ /; BlockModQ[x], y___] :=

Module[{a = Definition2[x][[1]], b = Headings[x], c = "", d}, a = StringReplace[a, b[[2]] <> " := " <> b[[1]] <> "[" –> ""]; Do[If[SyntaxQ[c = c <> StringTake[a, {j}]], Break[], 7], {j, Infinity}]; c = StringToList[StringTake[c, {2, –2}]]; If[{y} != {} && SymbolQ[y],

y = Map[{b = Quiet[Check[Flatten[StringPosition[#, "="]][[1]], {}]], If[b === {}, #, {StringTake[#, {1, b – 2}], StringTake[#, {b + 2, –1}]}]}[[2]] &, c], 7]; c]

In[3120]:= B[x_, y_] := Block[{a=5, b, c=7}, b = (a*x+b*c*y)/(x+y) +

Sin[x + y]; If[b, 45, b, a*c]] In[3121]:= SetAttributes[B, {Listable, Protected}]

In[3122]:= Locals6[B]

Out[122]= "{a = 5, b, c = 7}"

In[3123]:= Locals6[B, h7]

Out[3123]= {"a = 5", "b", "c = 7"} In[3124]:= h7

Out[3124]= {{"a", "5"}, "b", {"c", "7"}} In[3125]:= ModuleQ[StringReplaceVars]

Out[3125]= True

In[3126]:= Locals6[StringReplaceVars, g7]

Out[3126]= {"a = StringJoin[\"(\", S, \")\"]",

"L = Characters[\"`!@#%^&*(){}:\\\"\\\\/|<>?~=+[];:'., 1234567890_\"]", "R = Characters[\"`!@#%^&*(){}:\\\"\\\\/| <>?~=+[];:'., _\"]", "b", "c", "g = If[RuleQ[r], {r}, r]"}

In[3127]:= g7

Out[3127]= {{"a", "StringJoin[\"(\", S, \")\"]"},

{"L", "Characters[\"`!@#%^&*(){}:\\\"\\\\/|<>?~=+[];:'.,

1234567890_\"]"}, {"R", "Characters[\"`!@#%^&*(){}:\\\"\\\\/|

<>?~=+[];:'., _\"]"}, "b", "c", {"g", "If[RuleQ[r], {r}, r]"}}

Local variable processing tools are of particular interest in tasks of procedural programming. A number of other rather useful means for operating with local variables of both modules and blocks can be found in our books [7,10-16].

83

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

At last, it makes sense to mention one method of localization of variables in procedures that in certain situations can be quite convenient. The structural organization of such procedures can be presented as follows, namely:

G[Args] := Module[{}, Save[f, {a, b, c, …}]; Procedure body; {Res, Get[f], DeleteFile[f]}[[1]]]

A procedure can have a certain quantity of local variables or not have them in general whereas as other local variables any admissible variables are used, not excepting variables out of domain of the procedure, i.e. intersection of variables from the outside and in the procedure is allowed. For their temporary isolation (on runtime of the procedure) from external domain of the procedure their saving in a file f by Save function precedes the procedure body in which these variables are used like local variables. Whereas an exit from the procedure is made out by the three-element list where Res – a result of the procedure call, Get[f] – loading in the current session of file f with recovery of values of variables {a, b, c, …} that were until the procedure call with the subsequent deleting of file f. The following fragment illustrates the above mechanism of localization of variables.

In[19]:= {a, b} = {42, 77} Out[19]= {42, 77}

In[20]:= Gg[x_, y_] := Module[{}, Save["#$", {a, b, c}];

{a, b} = {47, 72}; {x*a/y*b, Get["#$"], DeleteFile["#$"]}[[1]]] In[21]:= Gg[30, 21]

Out[21]= 33840/7 In[22]:= {a, b, c} Out[22]= {42, 77, c}

At the same time, if the procedure has several possible exits then each exit should be issued in analogous way. In principle, the reception used for localization of variables described above within the framework of the procedure can be used not only in connection with its local variables.

In [15] we defined socalled active global variables as global variables to which in a Block, Module the assignments are done,

84

Mathematica: Functional and procedural programming

whereas we understand the global variables different from the arguments as the passive global variables whose values are only used in objects of the specified type. In this regard tools which allow to evaluate the passive global variables for the user blocks and modules are being presented as a very interesting. One of similar means the BlockFuncModVars procedure that solves even more general problem. The fragment represents the source code of the procedure BlockFuncModVars along with the most typical examples of its application.

In[24]:= BlockFuncModVars[x_ /; BlockFuncModQ[x]] :=

Module[{d, t, c = Args[x, 90], a = If[QFunction[x], {}, LocalsGlobals1[x]], s = {"System"}, u = {"Users"}, b = Flatten[{PureDefinition[x]}][[1]], h = {}}, d = ExtrVarsOfStr[b, 2];

If[a == {}, t = Map[If[Quiet[SystemQ[#]], AppendTo[s, #],

If[BlockFuncModQ[#], AppendTo[u, #], AppendTo[h, #]]] &, d]; {s, u = Select[u, # != ToString[x] &], c, MinusList[d, Join[s, u, c, {ToString[x]}]]}, Map[If[Quiet[SystemQ[#]], AppendTo[s, #],

If[BlockFuncModQ[#], AppendTo[u, #], AppendTo[h, #]]] &, d]; {Select[s, ! MemberQ[{"$Failed", "True", "False"}, #] &],

Select[u, # != ToString[x] && ! MemberQ[a[[1]], #] &], c, a[[1]], a[[3]], Select[h, ! MemberQ[Join[a[[1]], a[[3]], c, {"System", "Users"}], #] &]}]]

In[25]:= A[m_, n_, p_ /; IntegerQ[p], h_ /; PrimeQ[h]] :=

Module[{a = 77}, h*(m + n + p)/a + StringLength[ToString1[z]]/(Cos[c] + Sin[d])]

In[26]:= BlockFuncModVars[A]

Out[26]= {{"System", "Cos", "IntegerQ", "Module", "PrimeQ",

"Sin", "StringLength"}, {"Users", "ToString1"}, {"m", "n", "p", "h"},

{"a"}, {}, {"c", "d", "z"}}

The call BlockFuncModVars[x] returns the 6–element list, whose the 1st element the list of system functions used by block or module x, whose 1st element is "System", whereas other names are system functions in string format; the 2nd element the list of the user tools used by the block or module x, whose the 1st element is "User" while the others define names of tools in the string format; the 3rd element defines the list of formal arguments in the string format of the block or module x; the 4th element the list of local variables in the string format; the fifth element the list of active global variables in string format; at last, the sixth element determines the list of passive global variables in the string format of the block or module x.

85

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

2.5. Exit mechanisms of the user procedures (return results)

The procedure body implements a particular calculation or processing algorithm using control sentences of Math-language and its built–in functions along with other program tools. The result of successful execution of the procedure body is the exit from the procedure with purpose of return of its results to the current session of Mathematica system. In general, the return of results of procedure call can be organized by three manners: (1) through the last sentence of the procedure body, (2) through the system built–in Return function and (3) through its formal arguments, for example, procedures A, B and H accordingly:

In[7]:= A[x_] := Module[{a = 77, b = 72, c}, c = a + b; c*x]; A[1]

Out[7]= 149

In[8]:= B[x_, y_] := Module[{a = 77, b = 72, c}, c = a + b;

Return[77*x]; c*x; a*x + b*y]; B[1]

Out[8]= 77

In[9]:= H[x_, y_ /; ! ValueQ[y], z_ /; ! ValueQ[z]] := Module[{a = 77, b = 72, c}, c = a + b; y = c*x;

z = a*x^2; (a^2 + b^2)*x]; H[3, m, n]

Out[9]= 33339

In[10]:= {m, n} Out[10]= {447, 693}

Depending on the algorithm logic realized by a procedure body, the procedure allows the use of several Return functions that return results of the procedure (in general, the exit from the procedure) at the required algorithm points. In principle, the use of Return[] is allowed even in the list of local variables (starting values) as illustrates the following example:

In[27]:= B[x_, y_] := Module[{a = If[x < 10 && y > 10, x*y, Return[{x, y}]], b = 5, c = 7}, a*b*c]: B[5, 15]

Out[27]= 2625

In[28]:= B[15, 15]

Out[28]= {525, 525}

Whereas the third case can be used for returning of some additional results of the procedure call (values of local variables,

86

Mathematica: Functional and procedural programming

intermediate evaluations, etc). In the present book and in [1-15] a number of examples of such approach have been illustrated. At that, formal arguments in heading of a procedure thru that it is planned to return results has to be of the form {g_, g__, g___}

(i.e. without a testing Testg function) and be indefinite symbols on which ValueQ[g] call returns False, or be coded in the form g_/; !ValueQ[g]. For practical reasons, it is recommended to use the latter option to return the result thru formal g argument so as not to introduce unpredictability into the results of the current session: so, in a case of simple definite g variable the erroneous situation arises in attempt of assignment of value for g in the procedure while for g variable as a heading name in the current session arises the multiplicity of definitions for it as illustrates a rather simple fragment:

In[3]:= y[t_] := t^2; z[t_] := Module[{}, t^3]

In[4]:= H[x_, y_, z_] := Module[{}, y = x^2; z = x^3; x + 5];

H[3, y, z]

Out[4]= 8

In[5]:= Definition[y]

Out[5]= y = 9 y[t_] := t^2

In[6]:= Definition[z]

Out[6]= z = 27

z[t_] := Module[{}, t^3]

In[7]:= Clear[y, z]; {y, z} = {72, 77}; H[3, y, z]

Set::setraw: Cannot assign to raw object 72. Set::setraw: Cannot assign to raw object 77.

Out[7]= 8

Note that it is possible to use a mechanism represented by a fairly clear example to return intermediate results through the selected formal arguments with {__, ___} patterns:

In[2233]:= V[x_, y__] := Module[{a = 5, b = 7, c = {y}},

If[Length[c] >= 2, ToExpression[ToString[c[[1]]] <> "=77"]; ToExpression[ToString[c[[2]]] <> "=72"], ToExpression[ToString[c[[1]]] <> "=52"]]; (a + b)*x]

In[2234]:= Clear[b, c]; V[5, b, c]

87

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

Out[2234]= 60

In[2235]:= {b, c}

Out[2235]= {77, 72}

Mechanisms for returning the results of calling procedures through formal arguments, including updating them in situ, are of particular interest. Certain approaches have been presented above and in [30-38]. Meanwhile, for the Mathematica, certain difficulties represent, in particular, the cases when a list acts as a formal argument. As supportive tool in this case a procedure can be used, whose call SymbolValue[x, y] returns the list of the names in string format having a context y and a value x. While the call SymbolValue[x] returns the list of format {{"a'", {"a1",..., "an"}}, ..., {"j'", {"j1",...,"jm"}}} where the list {"a'",...,"j'"} defines contexts according to the variable $ContextPath and {"a1"...},..., {"j1"...} defines the names corresponding to them in the string format with value x. The fragment below represents the source code of the SymbolValue procedure with examples of its use.

In[42]:= L = {a, b, c, d, g, h, d, s, u, t} Out[42]= {a, b, c, d, g, h, d, s, u, t} In[43]:= M := {a, b, c, d, g, h, d, s, u, t}

In[44]:= SymbolValue[x_, y___] := Module[{b, c = {}, j,

a = Length[$ContextPath]}, If[{y} != {} && ContextQ[y],

Map[If[SameQ[ToExpression[#], x], #, Nothing] &, Names[y <> "*"]], b = Map[{#, Names[# <> "*"]} &, $ContextPath];

Do[AppendTo[c, {b[[j]][[1]],

Map[If[SameQ[ToExpression[#], x], #, Nothing] &, b[[j]][[2]]]}], {j, a}]; Map[If[#[[2]] == {}, Nothing, #] &, c]]]

In[45]:= SymbolValue[{a, b, c, d, g, h, d, s, u, t}, "Global`"]

Out[45]= {"L", "M"}

In[46]:= SymbolValue[{a, b, c, d, g, h, d, s, u, t}]

Out[46]= {{"SveGal`", {"L", "M"}}, {"Global`", {"L", "M"}}}

Consider an illustration of this approach on a simple example.

88

Mathematica: Functional and procedural programming

Trying to update the contents of the Ls list onto its sorted content in situ in the body of a Mn procedure with subsequent call of the procedure Mn[Ls] causes an erroneous diagnostics, and the Ls list itself obtains an incorrect value with output of erroneous messages. Whereas the procedure Mn1 using the above noted procedure SymbolValue successfully solves this problem, that the following rather simple and visual fragment illustrates.

In[77]:= Ls = {a, b, c, d, f, g, h, j, k, d};

In[78]:= Mn[x_List] := Module[{}, x = Sort[x]]

In[79]:= Mn[Ls]

$IterationLimit: Iteration limit of 4096 exceeded.

========================================

General: Further output of $IterationLimit::itlim will be suppressed during this calculation.

Out[79]= {a, b, c, Hold[g], Hold[g], Hold[h], Hold[j], Hold[k], Hold[d], Hold[f]}

In[80]:= Ls

$IterationLimit: Iteration limit of 4096 exceeded.

=======================================

General: Further output of $IterationLimit::itlim will be suppressed during this calculation.

Out[80]= {a, b, c, Hold[g], Hold[h], Hold[j], Hold[k],

Hold[d], Hold[f], Hold[g]}

Note that calling the built–in function ReleaseHold[x] that should removes Hold, HoldForm, HoldPattern, HoldComplete in x does not work in some cases, which illustrates an example

In[81]:= ReleaseHold[{a, b, c, Hold[g], Hold[h], Hold[j], Hold[k], Hold[d], Hold[f], Hold[g]}]

$IterationLimit: Iteration limit of 4096 exceeded.

=========================================

General: Further output of $IterationLimit::itlim will be suppressed during this calculation.

Out[81]= {a, b, c, Hold[j], Hold[k], Hold[d], Hold[f], Hold[g], Hold[h], Hold[j]}

In[81]:= Mn1[x_List] := Module[{},

ToExpression[SymbolValue[x, "Global`"][[1]] <> "=" <> ToString1[Sort[x]]]]

89

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

In[82]:= Mn1[Ls]

Out[82]= {a, b, c, d, d, f, g, h, j, k}

In[83]:= Ls

Out[83]= {a, b, c, d, d, f, g, h, j, k}

Further is being often mentioned about return of result of a function or a procedure as unevaluated that concerns both the standard built–in tools, and the user tools. In any case, the call of a procedure or a function on an inadmissible tuple of actual arguments is returned by unevaluated, except for the standard simplifications of the actual arguments. In this connection the UnevaluatedQ function providing testing of a procedure or a function regarding of the return of its call as unevaluated on a concrete tuple of actual arguments has been programmed. The function call UnevaluatedQ[F, x] returns True if the call F[x] will be returned unevaluated, and False otherwise; on an erroneous call F[x] "ErrorInNumArgs" is returned. The fragment presents source code of UnevaluatedQ function with examples of its use.

In[46]:= UnevaluatedQ[F_, x___] := If[! SymbolQ[F], True,

ToString1[F[x]] === ToString[F] <> "[" <> StringTake[ToString1[{x}], {2, -2}] <> "]"]

In[47]:= Sin[1, 2]

Sin: Sin called with 2 arguments; 1 argument is expected Out[47]= Sin[1, 2]

In[48]:= UnevaluatedQ[Sin, 77, 72]

Out[48]= "ErrorInArgs"

In[49]:= G[x_Integer, y_String] := y <> ToString[x] In[50]:= UnevaluatedQ[G, 77, 72]

Out[50]= True

The procedure presents an interest for program processing of the results of procedures and functions calls. The procedure was used by a number of means from our package [16].

As the results of exits from procedures, it is appropriate to consider also the various kinds of messages generated by the procedures as a result of erroneous and exceptional situations

(generated both by the system and programmed in the procedures). At the same time the issue of program processing of such messages is of a particular interest. In particular, the problem is solved by

90

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