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

KDP_book

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

Mathematica: Functional and procedural programming

Out[2435]= M[x_, y_] := Module[{}, x + y]

M[y_] := Module[{}, y^3]

M[x___] := Module[{}, {x}]

At the call of procedure or function of the same name from the list is chosen the one, whose formal arguments of heading correspond to actual arguments of the call, otherwise the call is returned unevaluated, excepting simplifications of arguments according to the standard system agreements. At compliance of formal arguments of heading with actual ones the component of x procedure or function is caused, whose definition is the first in the list returned at the call Definition[x]; particularly, whose definition has been evaluated in the Mathematica by the first. Therefore, in order to avoid possible misunderstandings in case of procedure override with a name x, which includes a change of its header also, the call Clear[x] must first undo the previous procedure definition.

The works [1-16] present a range of interesting software for dealing with the headings and formal arguments that make up them. In particular, the following tools can be mentioned:

ProcQ[x] returns True if x is a procedure and False otherwise; BlockModQ[x] returns True if x is a name defining a block or module; otherwise False is returned. At that, thru optional argument y an indefinite variable the call BlockModQ[x, y] returns the type of the object x in the context of {"Block", "Module"} on condition that

main result is True;

ArgsP[x] returns the list whose elements formal arguments of Block or Module x are grouped with the preceding words Block and Module. Groups arise in the case of multiple object definition x;

In[72]:= ArgsP[x_ /; BlockModQ[x]] := Module[{b, c = {}, j, a = Headings[x]}, a = If[MemberQ3[a, {"Module", "Block"}], a, {a}]; b = Length[a];

Do[Map[AppendTo[c, If[StringFreeQ[#, "["], #, StringReplace[StringTake[#, StringLength[#] 1], ToString[x] <> "[" > "{"] <> "}"]] &, a[[j]]], {j, 1, b}];

ToExpression[c]]

61

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

In[73]:= M[x_ /; IntegerQ[x]] := Module[{}, x^2];

M[x_, y_] := Module[{}, x*y^3]; M[x__] := Module[{}, {x}]; M[x_, y__] := Block[{a = 42, b = 47}, {a*x, b*y}]

In[74]:= ArgsP[M]

Out[74]= {Block, {x_, y__}, Module, {x_ /; IntegerQ[x]}, {x_, y_}, {x__}}

RenameP[x, y] returns the empty list, renaming a Function, Block or Module x to a name, defined by the second argument y with its activation in the current session; note, object x remains unchanged

In[32]:= RenameP[x_ /; BlockFuncModQ[x], y_Symbol] :=

ReplaceAll[ToExpression[Map[StringReplace[#, ToString[x] <> "[" > ToString[y] <> "[", 1] &, DefToStrM[x]]], Null > Nothing]

In[33]:= M[x_ /; IntegerQ[x]] := Module[{}, x^2];

M[x_, y_] := Module[{}, x*y^3]; M[x__] := Module[{}, {x}]; M[x_, y__] := Block[{}, {x, y}]

In[34]:= RenameP[M, Agn]

Out[34]= {}

In[35]:= Definition[Agn]

Out[35]= Agn[x_ /; IntegerQ[x]] := Module[{}, x^2]

Agn[x_, y_] := Module[{}, x*y^3] Agn[x_, y__] := Block[{}, {x, y}] Agn[x__] := Module[{}, {x}]

Note that we have programmed a lot of other useful tools for different processing of both the headings, as a whole, and their separate components, first of all, formal arguments [1-16]. Some of these are used in examples given in this book. Before further consideration, it should be noted once again that, the block and module headings handling tools are also functionally suitable for the classical functions determined by the headings according to a general mechanism used by the blocks, modules, and classical functions. Thus, what is said about the procedure headings fully applies to functions, making it easy to convert the second ones to the first.

One of the main tasks at working with formal arguments is

62

Mathematica: Functional and procedural programming

to define them for the user procedures (modules and blocks) and functions. In this direction, we have created a number of means of various purposes. At the same time, the definition of testing functions for formal arguments may itself contain definitions of procedures and functions, which implies consideration is given to this circumstance in the development of means of processing formal arguments. So, the ArgsProcFunc procedure considers this circumstance illustrating it on an example of its application to the M procedure presented below.

The procedure call ArgsProcFunc[x] generally returns the nested list whose single elements define formal arguments in the string format, and 2–element sublists by the first element define formal arguments, while by the second define the testing functions assigned to them (conditions of their admissibility) also in the string format of a procedure, block or function x.

In[1938]:= ArgsProcFunc[x_ /; BlockModQ[x]] := Module[{a = Definition1[x], b, c = "", d, j, f, g},

d = StringLength[g = ToString[x]]; c = g; For[j = d + 1, j <= StringLength[a], j++,

If[! SyntaxQ[g = g <> StringTake[a, {j, j}]], Continue[], Break[]]]; b = StringReplace[g, c <> "[" > ",", 1]; b = StringInsert[b, ",", 1]; c = "";

Do[c = c <> StringTake[b, {j, j}]; If[SyntaxQ[c], Break[], Continue[]], {j, 1, StringLength[b]}]; d = StringDrop[c, 2] <> ","; c = {};

Label[Agn]; f = StringPosition[d, ","]; f = DeleteDuplicates[Flatten[f]]; For[j = 2, j <= Length[f], j++,

If[SyntaxQ[g = StringTake[d, {f[[1]] + 1, f[[j]] 1}]],

AppendTo[c, g]; d = StringReplace[d, "," <> g > "", 1]; Goto[Agn], Continue[]]]; c = Map[StringReplace[#, GenRules[{"___", "__", " /;", "_:", "_.", "_"}, "@$@"], 1] &, c];

c = Map[StringTrim[#] &, Map[StringSplit[#, "@$@"] &, c]]; Map[If[Length[#] == 1, #[[1]], If[SuffPref[#[[2]], g = "/; ", 1], {#[[1]], StringReplace[#[[2]], g > "", 1]}, #]] &, c]]

63

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

In[1939]:= M[x_, y_ /; {g[t_] := Module[{}, t^2], If[g[y] > 50, True, False]}[[2]], r_: 77, p_., z___] := Module[{}, x*y*r*p/g[z]]

In[1940]:= {M[77, 8, 42, 72, 7], M[77, 7, 42, 72, 7]} Out[1940]= {38016, M[77, 7, 42, 72, 7]} In[1941]:= Definition[g]

Out[1941]= g[t_] := Module[{}, t^2] In[1942]:= ArgsProcFunc[M]

Out[1942]= {"x", {"y", "{g[t_] := Module[{}, t^2], If[g[y] > 50, True, False]}[[2]]"}, {"r", "77"}, "p", "z"}

It follows from the fragment that for a tool defined in the testing function of a formal argument, the availability domain is the entire current session, including the procedure body that generated it. ArgsProcFunc1 and ArgsProcFunc2 procedures, unlike ArgsProcFunc, are based on other principles, returning the lists of formal arguments with testing functions ascribed to them, while through the second optional argument is returned the same list with elements in the string format.

In[19]:= ArgsProcFunc1[x_ /; BlockFuncModQ[x], y___] := Module[{a = Definition1[x], b, c = "", d, j, f, g}, d = StringLength[g = ToString[x]]; c = g; For[j = d + 1, j <= StringLength[a], j++,

If[! SyntaxQ[g = g <> StringTake[a, {j, j}]], Continue[], Break[]]]; b = ToExpression["{" <> StringTrim[g, {c <> "[", "]"}] <> "}"];

If[{y} == {}, b, If[SymbolQ[y], b; y = Map[ToString1, b]]]]

In[20]:= ArgsProcFunc1[M, t]

Out[20]= {"x_", "y_ /; {g[t_] := Module[{}, t^2], If[g[y] > 50, True, False]}[[2]]", "r_:77", "p_.", "z___"}

In[77]:= ArgsProcFunc2[x_ /; BlockFuncModQ[x], y___] := Module[{a = ToExpression[HeadPFU[x]], b = {}, c, k},

Do[c = Quiet[Check[Part[a, k], Error, Part::partw]]; If[c === Error, Return[If[{y} == {}, b, If[SymbolQ[y], b; y = Map[ToString1, b], b]]], AppendTo[b, c]], {k, Infinity}]]

In[78]:= ArgsProcFunc2[M]

Out[78]= {x_, y_ /; {g[t_] := Module[{}, t^2], If[g[y] > 50, True, False]}[[2]], r_ : 77, p_., z___}

64

Mathematica: Functional and procedural programming

The question of processing of the formal arguments with good reason can be considered as the first problem relating to the calculations of the tuples of formal arguments of the user functions, modules and blocks that have been activated in the current session directly or on the basis of download of packages containing their definitions. In our works [1-15] certain tools for the solution of this problem have been programmed in the form of procedures Args, Args0÷Args2, then we presented similar tools in narrower assortment and with the improved some functional characteristics. Above all, as a rather useful tool, we present the Args3 procedure whose call Args3[x] returns the list of formal arguments of the user module, block or function x. At the same time, the argument x can present an multiple object of the same name. The following fragment represents the source code of the Args3 procedure with the most typical examples of its use.

In[3122]:= M[x_ /; SameQ[x, "avz"], y_] := Module[{a, b, c}, y]; M[x_ /; x == "avz"] := Module[{a, b, c}, x];

M[x_ /; IntegerQ[x], y_String] := Module[{a, b, c}, x];

M[x_, y_] := Module[{a, b, c}, "agn"; x + y]; M[x_String] := x; M[x_ /; ListQ[x], y_] := Block[{a, b, c}, "agn"; Length[x] + y]; F[x_ /; SameQ[x, "avz"], y_] := {x, y}

In[3123]:= Args3[s_ /; BlockFuncModQ[s]] :=

Module[{a = Headings[s], b, c = 7}, If[SimpleListQ[a], a = {a}, Set[c, 77]]; a = Map[#[[2]] &, a]; b = Map[StringReplace[#, ToString[s] –> "", 1] &, a]; b = Map[StringToList[StringTake[#, {2, –2}]] &, b];

If[c == 77, b, Flatten[b, 1]]]

In[3124]:= Args3[M]

Out[3124]= {{"x_ /; ListQ[x]", "y_"}, {"x_", "y_", "z_"},

{"x_ /; x === \"avz\"", "y_"}}

In[3125]:= Args3[F]

Out[3125]= {"x_ /; x === \"avz\"", "y_"} In[3126]:= Args3[L]

Out[3126]= {"x_", "y_"}

At that, in case of the returned nested list its sub-lists define tuples of formal arguments in the order that is defined by order of components of x object according to the call Definition[x].

65

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

The following procedure is an useful modification of our argument processing means. The call ArgsBFM1[x] generally returns the list of the ListList type whose two-element sublists in string format determine the name of a formal argument (1st element) and its admissibility test (2nd element) of block, function or module x. Lack of the test is coded as "Arbitrary"; in addition, under lack of test is understood not only its actual lack, but also the optional or default patterns ascribed to a formal argument. The procedure successfully processes the objects of the same name too, i.e. objects with several headings. The next fragment represents source code of the ArgsBFM1 procedure with typical examples of its application.

In[3336]:= ArgsBFM1[x_ /; BlockFuncModQ[x]] :=

Module[{b, c, d, g = {}, t, a = ToString2[Args[x]]}, a = If[QmultiplePF[x], a, {a}]; Do[{b, c, d} = {{}, {}, {}}; t = a[[j]];

Do[AppendTo[b, If[ListQ[t[[k]]], Map[StringSplit[#, {"/;", "__", "___", "_", ":", "_:", "_."}] &, t[[k]]],

StringSplit[t[[k]], {"/;", "__", "___", "_", ":", "_:", "_."}]]], {k, Length[t]}];

Do[AppendTo[c, If[NestListQ[b[[k]]], Map[Map[If[#1 == " " || #1 == "", Nothing, StringTrim[#1]] &, #] &, b[[k]]],

Map[If[# == " "||#1 == "", Nothing, StringTrim[#]] &, b[[k]]]]], {k, 1, Length[b]}];

Do[AppendTo[d, If[NestListQ[c[[k]]], Map[If[Length[#1] == 1, {#1[[1]], "Arbitrary"}, #1] &, c[[k]]], If[Length[c[[k]]] == 1, {c[[k]][[1]], "Arbitrary"}, c[[k]]]]], {k, 1, Length[c]}]; d = If[Length[d] == 1, d[[1]], d];

AppendTo[g, d], {j, Length[a]}]; If[Length[g] == 1, g[[1]], g]]

In[3337]:= G[x_, y_List, z_ : 77, h___] := Module[{g = 72}, Body]; G[x_, y_List, z_ : 78, {x1_, x2_List, x3_ : 90}, h___] :=

Module[{v = 42, g = 47, a = 87, k = 96, s = 67}, Body] In[3338]:= ArgsBFM1[G]

Out[3338]= {{{"x", "Arbitrary"}, {"y", "List"}, {"z", "78"},

{{"x1", "Arbitrary"}, {"x2", "List"}, {"x3", "90"}}, {"h", "Arbitrary"}}, {{"x", "Arbitrary"}, {"y", "List"}, {"z", "77"}, {"h", "Arbitrary"}}}

The procedure has a number of useful applications [8,16].

66

Mathematica: Functional and procedural programming

Several useful tools have been created to work with arguments of blocks, functions and modules [16]. One example is the procedure whose call Args2[x] returns the list of formal arguments with testing functions assigned to them in string format for a module, function, or block x. While calling Args2[x, y] with the second optional argument y – an undefined symbol via it returns the list consisting of 2element sublists whose elements in string format represent arguments and testing functions ascribed to them.

In[111]:= Default[Sg, 6, 42]; Sg[x_, y_Integer, z_ /; EvenQ[z], t__, h_: 0, g_.] := x*y + z + t + h*g

In[112]:= Args2[x_ /; BlockFuncModQ[x], y___] :=

Module[{a = Definition2[x][[1]], b = "", c, d = {}, t}, a = StringReplace5[a, {ToString[x] <> "[" –> "{", "] := " –> "}"}, 1]; Do[If[SyntaxQ[b = b <> StringTake[a, {j}]], Break[], 7], {j, Infinity}]; b = StringToList[StringTake[b, {2, –2}]]; If[{y} != {} && SymbolQ[y], c = Map[StringSplit[#, "_"] &, b]; y = Map[If[Length[#] == 1, AppendTo[d, #], If[SuffPref[#[[2]], t = " /; ", 1],

AppendTo[d, {#[[1]], StringReplace[#[[2]], t –> ""]}],

If[SuffPref[#[[2]], ":", 1], AppendTo[d, {#[[1]], "Optional"}], If[SuffPref[#[[2]], ".", 1], AppendTo[d, {#[[1]], "Default"}], AppendTo[d, #}]]]]] &, c]; y = DeleteDuplicates[Flatten[y, 1]]; y = Map[If[Length[#] == 1, #[[1]], #] &, y], 7]; b]

In[113]:= Args2[Sg, sv]

Out[113]= {"x_", "y_Integer", "z_ /; EvenQ[z]", "t__", "h_:0", "g_."} In[114]:= sv

Out[114]= {"x", {"y", "Integer"}, {"z", "EvenQ[z]"}, "t",

{"h", "Optional"}, {"g", "Default"}}

In[115]:= StringReplace5[x_String, y_ /; ListRulesQ[y], z_Integer] := Module[{a = x}, Do[a = StringReplace[a, y[[j]], z],

{j, Length[y]}]; a]

In[116]:= StringReplace5["12345612345", {"2" –> "a", "4" –> "b", "c" –> "d"}, 1]

Out[116]= "1a3b5612345"

The call StringReplace5[x, y, z] unlike the StringReplace of the same call format returns result of replacements only the first z entries of left part of each rule from a list y onto its right part in a string x.

67

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

It is worth noting that the permissibility of W constructions that include modules, blocks and functions including builtin ones, provided that BooleanQ[W] = True, makes it possible to conveniently include various kinds of diagnostic information in such constructs, as illustrated by the following simple example:

In[3337]:= T[x_ /; If[x > 50, {Print["Invalid first argument: it must be greater than 50"], False}, True],

y_ /; If[IntegerQ[y], True, Print["Invalid second argument: it must be an integer"]; False],

z_ /; If[PrimeQ[z], {g[t_] := t^2, True}[[2]], {Print["Invalid third argument: it must be a prime"], False}]] := g[x*y*z]

In[3338]:= T[100, 7, 7]

Invalid first argument: it must be greater than 50 Out[3338]= T[100, 7, 7]

In[3339]:= T[50, 42/77, 7]

Invalid second argument: it must be an integer Out[3339]= T[50, 6/11, 7]

In[3340]:= T[50, 77, 4]

Invalid third argument: it must be a prime Out[3340]= T[50, 77, 4]

In[3341]:= T[50, 77, 7]

Out[3341]= 72630250 In[3342]:= Definition[g]

Out[3342]= g[t_] := t^2

Thus, the testing function for a formal x argument can be an arbitrary expression w[x], for that the ratio BooleanQ[W[x]] = True will be true. Moreover, in addition to printing of diagnostic information, testing expressions w[x] may include definitions of modules, blocks and functions whose definitions are activated only if the actual argument x is valid, making their available in the body of an original procedure or function and in the current session as a whole. This possibility is illustrated in the above function T by the function g activated only at call T[x, y, z] with valid values for the formal arguments {x, y, z}. So, definitions of formal arguments of modules, blocks, functions allow a rather wide range of testing expressions to be used for them.

68

Mathematica: Functional and procedural programming

Here it is necessary to make an essential remark concerning the tools that deal with arguments of procedures and functions. The matter is that as it was shown earlier, testing tools ascribed to the formal arguments, as a rule, consist of the earlier defined testing functions or the reserved key words defining the type, for example, Integer. Whereas as a side effect the built-in Math– language allows to use the constructions that contain definitions of the testing means, directly in headings of the procedures and functions. Interesting examples of that have been represented above. Meanwhile, despite of such possibility, the programmed means are oriented, as a rule, on use for testing of admissibility of the factual arguments or the predefined means, or including the testing algorithms in the body of procedures and functions. For this reason, the Args procedure along with similar to it in such cases can return incorrect results. Whereas the procedure ArgsU covers such peculiar cases. The procedure call ArgsU[x] regardless of way of definition of testing of factual arguments in the general case returns the nested list whose elements are 3– element sub-lists of strings; the 1st element of such sub-lists is a name of formal argument, the second element defines template ascribed to this formal argument, and the 3rd element defines a testing function, construction including definition of the testing function, a key word, or an optional value, otherwise the third element is the empty string, i.e. "". The next fragment presents source code of the ArgsU procedure with examples of its use.

In[7]:= ArgsU[x_ /; BlockFuncModQ[x]] :=

Module[{a = HeadPFU[x], b, c, d = {}, g}, a = StringTake[a, {StringLength[ToString[x]] + 2, –2}]; c = StringPartition2[a, ","];

b[t_] := {StringTake[t, {1, Set[g, Flatten[StringPosition[t, "_"]][[1]]] – 1}],

StringTake[t, {g, –1}]}; c = Quiet[Map[StringTrim@b@# &, c]]; c = Quiet[Map[{#[[1]], StringReplace[#[[2]], " /; " –> "", 1]} &, c]];

Map[If[SuffPref[#[[2]], "___", 1], AppendTo[d, {#[[1]], "___", StringTrim2[#[[2]], "_", 1]}],

If[SuffPref[#[[2]], "__", 1], AppendTo[d, {#[[1]], "__", StringTrim2[#[[2]], "_", 1]}],

If[SuffPref[#[[2]], "_:", 1],

AppendTo[d, {#[[1]], "_:", StringReplace[#[[2]], "_:" –> "", 1]}],

69

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

If[SuffPref[#[[2]], "_.", 1], AppendTo[d, {#[[1]], "_.", StringReplace[#[[2]], "_." –> "", 1]}],

If[SuffPref[#[[2]], "_", 1], AppendTo[d, {#[[1]], "_", StringTrim2[#[[2]], "_", 1]}]]]]]] &, c];

If[Length[d] == 1, d[[1]], d]]

In[8]:= Ak[x_, h_ /; IntegerQ[h], y_ /; {IntOddQ[t_/; IntegerQ[t]] := Module[{}, IntegerQ[t] && OddQ[t]], IntOddQ[y]}[[–1]], p_ : 77, t_.] := x*y*h*p*t

In[9]:= Args[Ak]

ToExpression::sntx: Invalid syntax in or before

"{x_, h_ /; IntegerQ[h], y_ /; {IntOddQ[t_ /; IntegerQ[t]}". Out[9]= $Failed

In[10]:= ArgsU[Ak]

Out[10]= {{"x", "_", ""}, {"h", "_", "IntegerQ[h]"},

{"y", "_", "{IntOddQ[t_/; IntegerQ[t]] := Module[{}, IntegerQ[t] && OddQ[t]], IntOddQ[y]}[[–1]]"}, {"p", "_:", "77"}, {"t", "_.", ""}}

The ArgsTypes procedure [8] serves for testing of the formal arguments of block, function or module activated in the current session. So, the call ArgsTypes[x] returns the nested list, whose 2-element sub-lists in the string format define names of formal arguments and their admissible types (in the broader sense the tests for their admissibility with initial values by default) respectively. In lack of a type an argument it is defined as "Arbitrary" which is characteristic for arguments of pure functions and arguments without the tests and/or initial values ascribed to them and also which have format patterns {"__", "___"}. The fragment below represents source code of the ArgsTypes procedure along with typical examples of its application.

Moreover, the ArgsTypes procedure successfully processes the above cases "objects of the same name with various headings", returning the nested two-element lists of the formal arguments concerning the subobjects composing an object x, in the order defined by the Definition function. And in this case 2–element lists have the format, represented above while for objects with empty list of formal arguments the empty list is returned, i.e. {}. Unlike ArgsTypes of the same name this procedure processes objects, including pure functions and Compile functions.

70

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