Хостинг документов ученикам и учителям

## Mathematica: Functional and procedural programming

the Baltic branch

V. Vaganov

Functional and procedural programming in Mathematica

Second edition

Lulu Press – 2020

Functional and procedural programming in Mathematica.
V. Aladjev, M. Shishakov, V. Vaganov.
Lulu Press, 396 p., 2020.

Software presented in the book contains a number of useful and effective receptions of the procedural and functional programming in Mathematica that extend the system software and allow sometimes much more efficiently and easily to program the software for various purposes. Among them there are means that are of interest from the point of view of including of their or their analogs in Mathematica, at the same time they use approaches, rather useful in programming of various applications. In addition, it must be kept in mind that the classification of the presented tools by their appointment in a certain measure has a rather conditional character because these tools can be crossed substantially among themselves by the functionality.

The freeware package MathToolBox containing more 1420 tools is attached to the present book. The MathToolBox not only contains a number of useful procedures and functions, but can serve as a rather useful collection of programming examples using both standard and nonstandard techniques of functionalprocedural programming.

The book is oriented on a wide enough circle of the users from computer mathematics systems, researchers, teachers and students of universities for courses of computer science, physics, mathematics, and a lot of other natural disciplines. The book will be of interest also to the specialists of industry and technology which use the computer mathematics systems in own professional activity. At last, the book is a rather useful handbook with fruitful methods on the procedural and functional programming in the Mathematica system.

Mathematica 2, 5 ÷ 12.1.1.0 – trademarks of Wolfram Research Inc.

Printed by Lulu Press

December, 2020

Contents

Introduction 5

Chapter 1: The user functions in Mathematica 7

1.1. The user functions, defined intuitively 8

1.2. The user pure functions 12

1.3. Some useful tools for work with the user functions 20

Chapter 2: The user procedures in Mathematica 28

2.1. Definition of procedures in Mathematica software 29

2.3. Optional arguments of procedures and functions 57

2.4. Local variables in Mathematica procedures 71

2.5. Exit mechanisms of the user procedures 86

2.6. Tools for testing of procedures and functions 94

2.7. The nested blocks and modules 102

Chapter 3: Programming tools of the user procedure body 107

3.1. Branching control structures in the Mathematica 111

* Conditional branching structures 111

* Unconditional transitions 115

3.2. Cyclic control structures in the Mathematica 120

3.3. Some special types of cyclic control structures in

the Mathematica system 125

3.4. Mathematica tools for string expressions 130

* Replacements and extractions in strings 141

* Sub-strings processing in strings 143

* Expressions containing in strings 155

3.5. Mathematica tools for lists processing 160

3.6. Additional tools for the Mathematica 197

3.7. Attributes of procedures and functions 248

3.8. Additional tools expanding the built-in

Mathematica functions, or its software as a whole 254

3.9. Certain additional tools of expressions processing

in the Mathematica software 272

* Tools of testing of correctness of expressions 273

* Expressions processing at level of their components 277

* Replacement sub-expressions in expressions 285

* Expressions in strings 297

Chapter 4: Software for input-output in Mathematica 300

4.1. Tools of Mathematica for work with internal files 300

4.2. Tools of Mathematica for work with external files 305

4.3. Tools of Mathematica for attributes processing of

directories and data files 316

4.4. Additional tools for files and directories processing

of file system of the computer 323

4.5. Special tools for files and directories processing 333

Chapter 5: Organization of the user software 341

5.1. MathToolBox package for Mathematica system 345

5.2. Operating with the user packages in Mathematica 354

* The concept of context in Mathematica 355

* Interconnection of contexts and packages 363

5.3. Additional tools of operating with user packages 377

References 391

Book completes our multiyear cycle of book publications on general theory of statistics, computer science, cellular automata, Mathematica and Maple, with creation of software for the latest two computer mathematics systems Maple and Mathematica [42] and [16] accordingly.

used in any manner whatsoever without the express written permission of the
publisher except for the use of brief quotations in a book review or a scholarly
journal. This book completes a multi-year cycle of our publications in five areas
:
General theory of statistics, Information science, Cellular automata, Maple and
Mathematica along with creation of software for Maple and Mathematica.

The authors express deep gratitude and appreciation to Misters Uwe Teubel and Dmitry Vassiliev – the representatives of the firms REAG Renewable Energy AG & Purwatt AG (Switzerland) for essential assistance rendered by preparation of the present book.

Introduction

Systems of computer mathematics (SCM) find wide enough application in a whole number of natural, economic and social sciences such as: technologies, chemistry, informatics, mathematics, physics, education, economics, sociology, etc. Systems Mathematica and Maple, and some others are more and more demanded for learning of mathematically oriented disciplines, in scientifical researches and technologies. SCM are main tools for scientists, teachers, researchers, and engineers. The investigations on the basis of SCM, as a rule, well combine algebraical methods with advanced computing methods. In this sense, SCM are a certain interdisciplinary area between informatics and mathematics in which researches will be concentrated on the development of algorithms for algebraic (symbolical) and numerical calculations, data processing, and development of programming languages along with software for realization of algorithms of this kind and problems of different purpose basing on them.

It is possible to note that among modern SCM the leading positions are undoubtedly taken by the Maple and Matematica systems, alternately being ahead of each other on this or that indicator. The given statement is based on our longterm use in different purposes of both systems – Maple and Mathematica and also work on preparation and edition of the book series and some papers in Russian and English in this direction [1-42]. At the same time, as a result of expanded use of the above systems were created the package MathToolBox for Mathematica and library UserLib6789 for Maple [16,42]. All tools from the above library and package are supplied with freeware license and have open program code. Programming of many projects in Maple and Mathematica substantially promoted emergence of a lot of system tools from the above library and package. So, openness of MathToolBox package code allows both to modify the tools containing in it, and to program on their basis own tools, or to use their components in various appendices. Experience of use of library and package showed efficiency of such approach.

In particular, MathToolBox package contains more than 1420 tools of different purpose which eliminate restrictions of a number of standard tools of Mathematica system, and expand its software with new tools. In this context, this package can serve as a certain additional tool of procedural and functional programming, especially useful in the numerous appendices where certain nonstandard evaluations have to accompany programming. At that, tools represented in this package have a direct relationship to certain principal questions of procedural and functional programming in Mathematica system, not only for the decision of applied problems, but, above all, for creation of software extending frequently used facilities of the system, eliminating their defects or extending Mathematica with new facilities. The software presented in the package contains a lot of rather useful and effective receptions of programming in the Mathematica, and extends its software that allows to program the tasks of various purpose more simply and more effectively. A number of tools of the given package is used in the examples illustrating these or those provisions of the book.

In the book basic objects of programming in Mathematica functions and procedures are considered that consist the base of functionalprocedural programming. The given book considers some principal questions of proceduralfunctional programming in Mathematica, not only for decision of various applied tasks, but, as well, for creation of software expanding frequently used facilities of the system and/or eliminating their limitations, or expanding the system with new facilities. The important role of functions and procedures take place at creation of effective and intelligible user software in various fields. This also applies to software reliability.

The book is oriented on a wide enough circle of the users of the CMS, researchers, mathematicians, physicists, teachers and students of universities for courses of mathematics, computer science, physics, chemistry, etc. The book will be of interest to the specialists of industry and technology, economics, medicine and others too, that use the CMS in own professional activity.

Chapter 1: The user functions in Mathematica

Function is one of basic concepts of mathematics, being not less important object in programming systems, not excluding Mathematica system, with that difference that function as a subject to programming very significantly differs from strictly mathematical concept of function, considering specific features of programming in the Mathematica system.

Mathematica has a large number of functions of different purpose and operations over them. Each function is rather well documented and supplied with the most typical examples of its application. Unfortunately, unlike Maple, the program code of the Mathematica functions is closed that significantly narrows a possibility of deeper mastering the system and acquaintance with the receptions used by it and a technique of programming.

Truth, with rare exception, Mathematica allows to make assignments that override the standard builtin functions and meaning of Mathematica objects. However, program codes of the builtin functions of the system remain closed for the user. Names of builtin functions submit to some general properties, namely: names consist of complete English words, or standard mathematical abbreviations. In addition, the first letter of each name is capitalized. Functions whose names end with Q letter as a rule usually "ask a question", and return either True or False.

Many important functions of the Mathematica system can be found in our books [1-15], that provide detailed discussions of the built-in functions, the features of their implementation along with our tools [16] which expand or supplement them. A full arsenal of functionality can be found in the system manual. Here we will cover the basic issues of organizing user functions in Mathematica along with some tools that provide a number of important operations over user-defined functions. Moreover, it is possible to get acquainted with many of them in package MathToolBox [16] and in certain our books [1-15]. We pass to definition of the main functional user objects.

1.1. The classical functions, defined intuitively. Functions of this type are determines by expressions as follows:

(a) F[x_, y_, z_, ] := [x, y, z, ]

(b) F[x_ /; TestQ[x], y_, z_ /; TestQ[z], ] := [x, y, z, ]

Definition allows two formats (a) and (b) from which the first format is similar to the format of a classical mathematical function f(x, y, z, ...) = (x, y, z, ...) from n variables with that difference that for formal arguments x,y,z,... the object template are used _ which can designate any admissible expression of the system while (x,y,z,…) designate an arbitrary expression from variables x,y,z ..., including constants and function calls, for example:

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

In[1426]:= F[42, 78, 2020]

Out[1426]= 0.044062 + 3276*a*b

Whereas the second format unlike the first allows to hold testing of actual arguments obtained at function call F[x, y, z] for validity. It does a testing expression TestQ[x] attributed to formal argument e.g. x – if at least one testing expression on a relevant argument returns False, then function call is returned unevaluated, otherwise the function call returns the required value, if at evaluation of expression was no an erroneous or especial situation, for example:

In[8]:= F[x_ /; IntegerQ[x], y_, z_Symbol] := a*x*b*y + c*z

In[9]:= F[77, 90, G]

Out[9]= 6930*a*b + c*G

In[10]:= F[77, 90, 78]

Out[10]= F[77, 90, 78]

At the same time, for an actual argument its Head, e.g. List, Integer, String, Symbol, etc, as that illustrates the above example, can act as a test. At standard approach the concept of a function does not allow the use of local variables. As a rule Mathematica system assumes that all variables are global. This means that every time you use a name e.g. w, the Mathematica normally assumes that you are referring to the same object. However, at program writing, you may not want all variables to be global. In this case, you need the w in different points of a program to be treated as a local variable. At the same time, local variables in function definition can be set using modules. Within module you can give a list of variables which are to be treated as local. This goal can be achieved with help of blocks too. A simple example illustrates the told:

In[47]:= F[x_, y_] := x*y + Module[{a = 5, b = 6}, a*x + b*y]

In[48]:= F[42, 78]

Out[48]= 3954

In[49]:= {a, b} = {0, 0}

Out[49]= {0, 0}

In[50]:= F[42, 78]

Out[50]= 3954

In[51]:= S[x_, y_] := x*Block[{a = 5, b = 6}, a/b*y^2]

In[52]:= S[42, 48]

Out[52]= 80640

In[53]:= {a, b} = {0, 0}; S[42, 48]

Out[53]= 80640

In addition, pattern object "___" or "__" is used for formal arguments in a function definition can stand for any sequence of zero or more expressions or for any nonempty sequence of expressions accordingly, for example:

In[2257]:= G[x__] := Plus[x]

In[2258]:= G[500, 90, 46]

Out[2258]= 636

In[2259]:= G1[x___] := Plus[x]

In[2260]:= {G1[], G1[42, 47, 67]}

Out[2260]= {0, 156}

Lack of such definition of function is that the user cannot use local variables, for example, the coefficients of polynomials and other symbols other than calls of standard functions or local symbols determined by the artificial reception described above (otherwise function will depend on their current values in the current session with Mathematica system). So, at such function definition expression should depend only on formal arguments. But in a number of cases it is quite enough. This function definition is used to give a more complete view of this object and in certain practical cases it is indeed used [9-12,16].

Meanwhile, using our procedure [16] with program code:

In[2274]:= Sequences[x__] := Module[{a = Flatten[{x}], b},

b = "Sequence[" <> ToString1[a] <> "]";

a = Flatten[StringPosition[b, {"{", "}"}]];

ToExpression[StringReplace[b, {StringTake[b, {a[[1]],

a[[1]]}] > "", StringTake[b, {a[[1]], a[[1]]}] > ""}]]]

that extends the standard built-in Sequence function and useful in many applications, it is possible to represent another way to define the user functions, modules, and blocks, more precisely their headers based on constructions of the format:

<Function name>@Sequences[formal args] :=

The following a rather simple example illustrates the told:

In[75]:= G@Sequences[a_Integer, b_Symbol, c_] := a+b+c

In[76]:= Definition[G]

Out[76]= G[a_Integer, b_Symbol, c_] := a + b + c

In[77]:= G[6.7, 5, 7]

Out[77]= G[6.7, 5, 7]

In[78]:= G[67, m, 7]

Out[78]= 74 + m

Naturally, in real programming, this definition of functions is not practical, serving only the purposes of possible methods of defining said objects. In the meantime, such extension of the built-in tool allows comparing the capabilities of both tools in determining the underlying objects of the system.

Along with the above types of functions, the Mathematica uses also the Compile function intended for compilation of the functions which calculate numeric expressions at quite certain assumptions. The Compile function has the 4 formats of coding, each of which is oriented on a certain compilation type:

Compile[{x1, x2,…}, G] compiles a function for calculation of an expression G in the assumption that all values of arguments xj {j =

1, 2, } have numerical character;

Compile[{{x1, t1}, {x2, t2}, {x3, t3}, }, G] compiles a function for calculation of an expression G in the assumption that all values of xj arguments have type tj {j = 1, 2, 3,…} accordingly;

Compile[{{x1, p1, w1}, {x2, p2, w2},…}, J] compiles a function for calculation of an expression J in the assumption that values of xj arguments are wj ranks of array of objects, each of that corresponds to a type pj {j = 1, 2, 3,…};

Compile[s, W, {{p1, pw1}, {{p2, pw2}, }] compiles a function for calculation of a certain expression W in the assumption that its s sub-expressions that correspond to the pk templates have the pwj types accordingly {k = 1, 2, 3, }.

The Compile function processes procedural and functional objects, matrix operations, numeric functions, functions for lists processing, etc. Each Compile function generates a special object CompiledFunction. The function call Compile[…, Evaluate[w]] is used to specify the fact that w expression should be evaluated symbolically before compilation. For testing of functions of this type a rather simple CompileFuncQ function is used [8], whose call CompileFuncQ[x] returns True if a x represents the Compile function, and False otherwise. The fragment represents source code of the CompileFuncQ function with examples of its use.

In[7]:= V := Compile[{{x, _Real}, {y, _Real}}, x*y]; K := (#1*#2) &;

A := Function[{x, y}, x/y]; H[x_] := Block[{}, x]; H[x_, y_] := x + y;

SetAttributes["H", Protected]; P[x__] := Plus[Sequences[{x}]];

GS[x_ /; IntegerQ[x], y_ /; IntegerQ[y]] := Sin[78] + Cos[42];

Sv[x_ /; IntegerQ[x], y_ /; IntegerQ[y]] := x^2 + y^2;

Sv = Compile[{{x, _Integer}, {y, _Real}}, (x + y)^6];

S := Compile[{{x, _Integer}, {y, _Real}}, (x + y)^3];

G = Compile[{{x, _Integer}, {y, _Real}}, (x/y)];

In[8]:= CompileFuncQ[x_] := If[SuffPref[ToString1[Definition3[x]],

"Definition3[CompiledFunction[{", 1], True, False]

In[9]:= Map[CompileFuncQ, {Sv, S, G, V, P, A, K, H, GS, Sv}]

Out[9]= {True, True, True, True, False, False, False, False, False, True}

The CompileFuncQ function expands testing possibilities of the functional objects in Mathematica, by representing a certain interest first of all for the system programming.

Thus, as a reasonably useful version of the built-in Compile function, one can represent the Compile1 procedure whose call Compile1[f, x, y] returns a function of the classical type whose body is defined by an algebraic y expression, whereas f defines a name of the generated function and x defines the list of types attributed to the parameters of an expression y. The factual x argument is specified in the format {{a, Ta}, b, {c, Tc},…}, where {a, b, c,…} defines parameters of the y expression, whereas {Ta, Tc,…} defines the testing Q-functions while single elements of x defines validity of any expression for corresponding parameter.

In[10]:= Compile1[f_ /; SymbolQ[f], x_ /; ListQ[x], y_] :=

Module[{a = ToString1[y], b, c, d, g, h, t}, b = FactualVarsStr1[a];

b = Select[b, ! SameQ[#[[1]], "System`"] &][[1]][[2 ;–1]];

SetAttributes[g, Listable]; g[t_] := ToString[t];

t = Map[ToString, Map[If[ListQ[#], #[[1]], #] &, x]];

c = ToString[f] <> "["; d = Map[g, x];

Do[h = d[[j]]; If[ListQ[h] && MemberQ[b, h[[1]]],

c = c <> h[[1]] <> "_ /;" <> h[[2]] <> "[" <> h[[1]] <> "],",

If[MemberQ[b, h], c = c <> h <> "_ ,", 77]], {j, Length[d]}];

t = Complement[b, t];

If[t != {}, Do[c = c <> t[[j]] <> "_ ,", {j, Length[t]}], 78];

c = StringTake[c, {1, –2}] <> "] := " <> a; ToExpression[c];

Definition[f]]

In[11]:= Compile1[f, {x, {n, IntegerQ}, {M, RationalQ}, {h, RealQ}},

(Sin[h] + a*x^b)/(c*M – Log[n])]

Out[11]= f[x_, n_/; IntegerQ[n], M_/; RationalQ[M], h_/; RealQ[h],

a_, b_, c_] := (a*x^b + Sin[h])/(c*M Log[n])

In[12]:= N[f[t, 77, 7/8, 7.8, m, n, p], 3]

Out[12]= (0.998543 + m*t^n)/(4.34 + 0.875*p)

Fragment above represents source code of the procedure.

1.2. The user pure functions. First of all, we will notice that so–called functional programming isn't any discovery of the Mathematica system, and goes back to a number of software that appeared long before the above system. In this regard, it is pertinently focused slightly more in details the attention on the concept of functional programming in historical aspect. While here we only will note certain moments characterizing specifics of the paradigm of functional programming. We will note only that the foundation of functional programming has been laid approximately at the same time, as imperative programming that is the most widespread now, i.e. in the thirties years of the last century. A. Church (USA) the author of λ–calculus and one of founders of the concept of Cellular Automata in connection with his works in field of infinite automata and mathematical logic along with H. Curry (England) and M. Schönfinkel (Germany) that have developed the mathematical theory of combinators, with good reason can be considered as the founders of mathematical foundation of functional programming. In addition, functional programming languages, especially the purely functional ones such as the Hope and Rex, have largely been used in academical circles rather than in commercial software. Whereas prominent functional programming languages such as Lisp have been used in the industrial and commercial applications. Today, functional programming paradigm is also supported in a number of domain-specific programming languages, for example, by the Mathem–language of the Mathematica. From a rather large number of languages of functional programming it is possible to note the following languages that exerted a great influence on progress in this field, namely: Lisp, Scheme, ISWIM, family ML, Miranda, Haskell, etc. By and large, if the imperative languages are based on operations of assignment and cycle, the functional languages on recursions. The most important advantages of the functional languages are considered in our books in detail [8-14], namely:

programs on functional languages as a rule are much shorter and simpler than their analogues on the imperative languages;

almost all modern functional languages are strictly typified and ensure the safety of programs; at that, the strict typification allows to generate more effective code;

in a functional language the functions can be transferred as an argument to other functions or are returned as result of their calls;

in pure functional languages (which aren't allowing by–effects for the functions) there is no an operator of assigning, the objects of such language can't be modified or deleted, it is only possible to create new objects by decomposition and synthesis of the existing objects. In the pure functional languages all functions are free from byeffects.

Meanwhile, functional languages can imitate certain useful imperative properties. Not every functional language are a pure forasmuch in a lot of cases the admissibility of byeffects allows to essentially simplify programming. However, today the most developed functional languages are as a rule pure. With many interesting enough questions concerning a subject of functional programming, the reader can familiarize oneself, for example, in [15]. Whereas with an quite interesting critical remarks on functional languages and possible ways of their elimination it is possible to familiarize oneself in [8-15,22].

A number of concepts and paradigms are quite specific for functional programming and absent in imperative programming. Meanwhile, many programming languages, as a rule, are based on several paradigms of programming, in particular imperative programming languages can successfully use also concepts of functional programming. In particular, as an important enough concept are so–called the pure functions, whose results of run depends only on their actual arguments. Such functions possess certain useful properties a part of which it is possible to use for optimization of program code and parallelization of calculations. In principle, there are no special difficulties for programming in the functional style in languages that aren't the functional. The Mathematica language supports the mixed paradigm of functional and procedural programming. We will consider the elements of functional programming in Mathematica in whose basis the concept of the pure function lays. The pure functions one of the basic concepts of functional programming which is a component of programming system in Mathematica in general.

Typically, when a function is called, its name is specified, whereas pure functions allow specifying functions that can be applied to arguments without having to define their explicit names. If a certain function G is used repeatedly, then can define the function using definition, considered above, and refer to the function by its name G. On the other hand, if some function is intend to use only once, then will probably find it better to give the function in format of pure function without ever naming it. The reader that is familiar with formal logic or the LISP programming language, will recognize Mathematica pure functions as being like λ expressions or not named functions. Note, that pure functions are also close to the pure mathematical notion of operators. Mathematica uses the following formats for definition of pure functions, namely:

(a) Function[x, body]

(b) Function[{x1, x2, …, xn}, body]

(c) body &

Format (a) determines pure function in which x in function body is replaced by any given argument. An arbitrary admissible expression from variable x, including also constants and calls of functions acts as a body. Format (b) determines a pure function in which variables x1, x2, …, xn in function body is replaced by the corresponding arguments. Whereas format (с) determines a function body containing formal arguments denoted as # or #1, #2, #3, etc. It is so-called short format. Note, the pure functions of formats (a), (b) do not allow to use the typification mechanism for formal arguments similarly to the classical functions, namely constructs of type "h_..." are not allowed. This is a very serious difference between pure function and classical function whereas otherwise, already when evaluating the definition of any pure function with typed formal arguments, Mathematica identifies the erroneous situations.

The calls of pure functions of the above formats are defined according to simple examples below, namely:

In[2162]:= Function[x, x^2 + 42][25]

Out[2162]= 667

In[2163]:= Function[{x, y, z}, x^2 + y^2 + z^2][42, 75, 78]

Out[2163]= 13473

In[2164]:= #1^2 + #2^2 &[900, 50]

Out[2164]= 812500

In[2165]:= Function[x_Integer, x^2 + 42]

Function::flpar: Parameter specification x_Integer in

When Function[body] or body & is applied to a set of formal arguments, # (or #1) is replaced by the first argument, #2 by the second, and so on while #0 is replaced by the function itself. If there are more arguments than #j in the function supplied, the remaining arguments are ignored. At that, ## defines sequence of all given arguments, whereas ##n stands for arguments from number n onward. Function has attribute HoldAll and function body is evaluated only after the formal arguments have been replaced by actual arguments. Function construct can be nested in any way. Each is treated as a scoping construct, with named inner variables being renamed if necessary. Furthermore, in the call Function[args, body, attrs] as optional argument attrs can be a single attribute or a list of attributes, e.g. HoldAll, Protected and so on, while the call Function[Null, body, attrs] represents a function in which the arguments in function body are given using slot #, etc. Such format of a pure function is very useful when a onetime call of the function is required.

Note that unlike the format (c), the formats (a) and (b) of a pure function allow use as the body rather complex program constructions, including local variables, cycles and definitions of blocks, modules and functions. A simple enough example quite visually illustrates what has been said:

In[7]:= {a, b} = {0, 0}

Out[7]= {0, 0}

In[8]:= Function[{x, y, z}, Save["t", {a, b}]; {a, b} = {42, 47};

g[h_, g_] := h*g; If[x <= 6, Do[Print[{a, b, y^z}], z], x+y+z];

{(a+b)*(x+y+z) + g[42, 47], Get["t"], DeleteFile["t"]}[[1]]][1, 2, 3]

{42, 47, 8}

{42, 47, 8}

{42, 47, 8}

Out[8]= 2508

In[9]:= {a, b}

Out[9]= {0, 0}

In[10]:= g[42, 47]

Out[10]= 1974

So, in the given example the locality of variables a and b is provided with saving their initial (up to a function call) values at the time of function call by their saving in the temporary "tmp" file, their redefinitions in the course of execution of a function body with the subsequent uploading of initial values of a and b from the "tmp" file to the current session of Mathematica with removal of the "tmp" file from the file system of the computer. Such mechanism completely answers the principle of locality of variables in a function body. This example also illustrates the ability to define a new function in the body of a pure function with its use, both within the body of the source function and outside of the function.

At using of the pure functions, unlike traditional functions, there is no need to designate their names, allowing to code their definitions directly in points of their call that is caused by that the results of the calls of pure functions depend only on values of the actual arguments received by them. Selection from a list x of elements that satisfy certain conditions and elementwise application of a function to elements of the list x can be done by constructions of the view Select[x, test[#] &] and Map[F[#] &, x] respectively as illustrate the following examples, namely:

In[3336]:= Select[{a, 72, 77, 42, 67, 2019, s, 47, 500}, OddQ[#] &]

Out[3336]= {77, 67, 2019, 47}

In[3337]:= Map[(#^2 + #) &, {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}]

Out[3337]= {2, 6, 12, 20, 30, 42, 56, 72, 90, 110, 132, 156}

At use of the short form of a pure function it is necessary to be careful at its coding because the ampersand (&) has quite low priority. For example, expression #1 + #2 #3 + #2*#4 & without parentheses is correct whereas, in general, they are obligatory, in particular, at use of a pure function as the right part of a rule as illustrate very simple examples [10-12]. The universal format of a call of pure f function is defined as f @@ {args}, for instance:

In[4214]:= OddQ[#] || PrimeQ[#] || IntegerQ[#] & @@ {78}

Out[4214]= True

In combination with a number of functions, in particular, Map, Select and some others the use of pure functions is rather convenient, therefore the question of converting the traditional functions into the pure functions seems an quite topical; for its decision various approaches, including creation of the program converters can be used. Thus, we used pure functions a rather widely at programming of a lot of problems of various types of the applied, and the system character [1-16,22].

Unlike a number of convertors of classical functions to pure function, procedure below allows to keep the testing functions of the general kind for arguments of the converted functions

W[x_ /; Test[x], y_H, z_, h__H1, t__, ] := [x, y, z, h, t, ]

by converting of a classical W function to pure function of short format, i.e. the procedure call FuncToPureFunction[W] returns the pure function in the following kind

If[Test[#1] && HQ[#2] && True && H1Q[#4] && True && …, [#1, #2, #3, #4, #5, ], IncorrectArgs[Sequential numbers of incorrect factual arguments]] &

where {heads H and H1} can absent. In addition, for arguments of type {h__H1, t__} the resultant pure function considers only their first factual value. At the same time, only one of the {Real, List, Complex, Integer, Rational, String, Symbol} list is allowed as a head H for a y expression. In a case of inadmissibility of at least one argument and/or its testing (for example, incorrect head H or H1) the call of the pure function returns the formal call of the kind IncorrectArgs[n1, n2,…, np], where {n1, n2,…, np} determine sequential numbers of incorrect arguments. With source code of the FuncToPureFunction procedure with typical examples of its application that a quite clearly illustrate the results returned by the procedure can be found below [8-12,16].

In[5]:= FuncToPureFunction[x_ /; FunctionQ[x]] :=

Module[{a, b = ProcBody[x], c = 1, d, g, h, p, s = Map[ToString,

{Complex, Integer, List, Rational, Real, String, Symbol}]},

a = ArgsBFM1[x]; g = Map[{Set[d, "#" <> ToString[c++]]; d,

StringReplaceVars[#[[2]], #[[1]] –> d]} &, a];

h = Map[If[! StringFreeQ[#[[2]], #[[1]]], #[[2]],

If[#[[2]] == "Arbitrary", "True", If[MemberQ[s, #[[2]]], #[[2]] <>

"Q[" <> #[[1]] <> "]", "False"]]] &, g];

p = Map["(" <> # <> ")" &, h]; p = Riffle[p, "&&"];

a = Map[#[[1]] &, a]; c = Map[#[[1]] &, g];

a = StringReplaceVars[b, GenRules[a, c]];

ToExpression["If[" <> p <> "," <> a <> "," <>

"IncorrectArgs@@Flatten[Position[" <>

ToString[h] <> ", False]]" <> "]&"]]

In[6]:= f[x_ /; IntegerQ[x], y_ /; y == 77, z_List, t_, p__, h___] :=

x*y*h + Length[z]*t

In[7]:= FuncToPureFunction[f]

Out[7]= If[IntegerQ[#1] && #2 == 77 && ListQ[#3] && True && True && True, #1*#2*#6 + Length[#3]*#4, IncorrectArgs @@ Flatten[Position[{IntegerQ[#1], #2 == 77, ListQ[#3], True, True, True}, False]]] &

It should be noted that pure functions allow for a kind of parameterization based on constructions of the following format:

<Name[params]> := <Pure function, containing params>

where Name a name of pure function and params determines parameters entering the function body. Calls of pure functions parameterized in this way have the following format:

Name[params][actual args]

The following simple example illustrates the told:

In[2215]:= T[n_, m_] := Function[{x, y, z}, n*(x + m*y + z)]

In[2216]:= T[42, 47][1, 2, 3]

Out[2216]= 4116

In[2217]:= G[p_, n_] := p*(#1^2 + #2^2*#3^n) &

In[2218]:= G[5, 2][5, 6, 7]

Out[2218]= 8945

In[2219]:= With[{p=5, n=2}, p*(#1^2 + #2^2*#3^n) &][5,6,7]

Out[2219]= 8945

In a number of applications such parameterization is quite useful, allowing customizing the tool for application based on parameter values. Some useful tools for working with the user functions are presented below, whereas a wider range of such tools are available for classical functions which are suitable also for many user procedure processing. This should be borne in mind when discussing issues related to the procedures.

1.3. Some useful tools for work with the user functions. For work with functions Mathematica has a wide range of tools for working with functions, including user ones. Here we present a number of tools for working with user functions that do not go to the standard set. First of all, it is of particular interest to test a symbol or expression to be a function. Some of the tools in this direction are presented in our package MathToolBox [16,9-12]. The most common tool of this type is the function FunctionQ, whose definition in turn contains QFunction and QFunction1 procedures and function PureFuncQ of the same type, whose call on a symbol or expression x returns True, if x is a function and False otherwise. Program code of the FunctionQ function can be presented as follows:

In[25]:= FunctionQ[x_] := If[StringQ[x], QFunction1[x] ||

PureFuncQ[ToExpression[x]], PureFuncQ[x] || QFunction[x]]

In[26]:= y := #1^2 + #2^2 &; {FunctionQ[#1^2 + #2^2 &],

FunctionQ[y]}

Out[26]= {True, True}

In[27]:= z = Function[{x, y, z}, If[x <= 6, Do[Print[y^z], z],

x + y + z]];

In[28]:= FunctionQ[Function[{x, y, z}, If[x <= 6,

Do[Print[y^z], z], x + y + z]]]

Out[28]= True

In[29]:= FunctionQ[z]

Out[29]= True

In[30]:= PureFuncQ[Function[{x, y, z}, If[x <= 6,

Do[Print[y^z], z], x + y + z]]]

Out[30]= True

In[31]:= PureFuncQ[#1^2 + #2^2 &]

Out[31]= True

In[32]:= G[x_] := Plus[Sequences[x]]

In[33]:= {FunctionQ[G], PureFuncQ[G]}

Out[33]= {True, False}

At the same time, the function call PureFuncQ[w] allows to identify object w to be a pure function, returning True, if w is a pure function and False otherwise. This tool along with others provides strict differentiation of such basic element of functional and procedural programming, as a function [8-16].

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]] <> "&"],

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};

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"}

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.

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 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 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.

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.

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.

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.

In the context of testing blocks for procedural nature in the above sense, the LocVars1 procedure may be of interest whose call LocVars1[x] returns True if x is a module or a block x has no local variables without initial values, or the list of local variables is empty, otherwise False is returned. While calling LocVars1[x,y] with the 2nd optional argument y an undefined symbol through y additionally returns the 2-element list whose the first element defines the list of all local variables of x, while the 2nd element defines the list of local variables without initial values. Below, fragment represents source code of the procedure with its use.

In[4]:= LocVars1[x_ /; BlockModQ[x], y___] := Module[{a, b, d = {}},

a = Locals5[x, b];

Do[AppendTo[d, If[Length[b[[k]]] < 2, a[[k]], Nothing]],

{k, Length[a]}]; If[{y} != {} && SymbolQ[y], y = {a, d}, 7];

If[ModuleQ[x], True, If[a == d, True, False]]]

In[5]:= B[x_] := Block[{a = 7, b, c = 8, d}, x*a*b*c*d];

B1[x_] := Block[{a, b, c, d}, x*a*b*c*d]

In[6]:= {LocVars1[B, t1], t1}

Out[6]= {False, {{"a = 7", "b", "c = 8", "d"}, {"b", "d"}}}

In[7]:= {LocVars1[B1, t2], t2}

Out[7]= {True, {{"a", "b", "c", "d"}, {"a", "b", "c", "d"}}}

In[8]:= G[x_] := Block[{}, x^2]; {LocVars1[G, t72], t72}

Out[8]= {True, {{}, {}}}

Considering importance of modular approach to software organization when a program code consists of set of the linked independent objects and reaction of objects is defined only by their inputs, in this quality to us the most preferable the modules are presented. In general software code of the modular structure, the output of the module is the input for another module. For this reason the lion share of tools of our package MathToolBox [16] is programmed in the form of modules.

Once again, pertinently to pay attention to one moment. A number of tools represented in the package are focused on the solution of identical problems, but they use various algorithms programmed with usage of various approaches. They not only illustrate variety of useful enough receptions but also revealing their shortcomings and advantages useful both in practical and system programming. In our opinion, such approach opens a rather wide field for awakening of creative activity of the reader in respect of improvement of his skills in the programming in Mathematica system. Now let's consider module components in more detail.

Let's note that in certain cases duplication of definitions of blocks, modules and functions under new names on condition of saving their former definitions invariable is required. So, for assignment of a name that is unique in the current session to the new means, the procedure whose call DupDef[x] returns a name (unique in the current session) whose definition will be equivalent to definition of the x symbol can be used. In addition, the given procedure successfully works with the means having multiple definitions too. The following fragment represents source code of the procedure with an example of its application.

In[3331]:= DupDef[x_ /; BlockFuncModQ[x]] :=

Module[{a = Flatten[{Definition1[x]}],

b = Unique[ToString[x]]},

ToExpression[Map[StringReplace[#, ToString[x] <> "[" >

ToString[b] <> "[", 1] &, a]]; b]

In[3332]:= Gs[x_, y_] := x + y

In[3333]:= Gs[x_] := Module[{a = 77}, a*x^2]

In[3334]:= DupDef[Gs]

Out[3334]= Gs78

In[3335]:= Definition[Gs78]

Out[3335]= Gs78[x_, y_] := x + y

Gs78[x_] := Module[{a = 77}, a*x^2]

In particular, the DupDef procedure is useful enough when debugging of the user software.

The call Definition[x] of the standard function in a number of cases returns the definition of some x object with the context corresponding to it what at a rather large definitions becomes badly foreseeable and less acceptable for subsequent program processing as evidently illustrates a number of examples [6-15]. Moreover, the name of an object or its string format also can act as an actual argument. For elimination of this shortcoming we defined a number of tools allowing to obtain definitions of the procedures or functions in a certain optimized format. As such means it is possible to note the following: DefOptimum, DefFunc, Definition1, Definition2, Definition3 ÷ Definition5, DefFunc1, DefOpt, DefFunc2 and DefFunc3. These means along with some others are represented in [4-9] and included in the MathToolBox package [16]. The following fragment represents the source code of the most used tool of them with an example of its application.

In[49]:= Definition2[x_ /; SameQ[SymbolQ[x], HowAct[x]]] :=

Module[{a, b = Attributes[x], c},

If[SystemQ[x], Return[{"System", Attributes[x]}],

Off[Part::partw]]; ClearAttributes[x, b];

Quiet[a = ToString[InputForm[Definition[x]]];

Mapp[SetAttributes, {Rule, StringJoin}, Listable];

c = StringReplace[a, Flatten[{Rule[StringJoin[Contexts1[],

ToString[x] <> "`"], ""]}]]; c = StringSplit[c, "\n \n"];

Mapp[ClearAttributes, {Rule, StringJoin}, Listable];

SetAttributes[x, b]; a = AppendTo[c, b];

If[SameQ[a[[1]], "Null"] && a[[2]] == {}, On[Part::partw];

{"Undefined", Attributes[x]}, If[SameQ[a[[1]], "Null"] &&

a[[2]] != {} && ! SystemQ[x], On[Part::partw]; {"Undefined",

Attributes[x]}, If[SameQ[a[[1]], "Null"] && a[[2]] != {} &&

a[[2]] != {}, On[Part::partw]; {"System", Attributes[x]},

On[Part::partw]; a]]]]]

In[50]:= a[x_] := x + 6; a[x_, y_] := Module[{}, x/y]; a[t_Integer] := 7

In[51]:= SetAttributes[a, {Protected, Listable}]; Definition2[a]

Out[51]= {"a[t_Integer] := 7", "a[x_] := x + 6",

"a[x_, y_] := Module[{}, x/y]", {Listable, Protected}}

The Definition2 call on system functions returns the nested list, whose first element "System", while the second element – the list of attributes ascribed to a factual argument. On the user function or procedure x the call Definition2[x] also returns the nested list, whose first element the optimized definitions of x (in the sense of absence of contexts in them, at a series definitions in a case of multiplicity of x definition), whereas the second element the list of attributes ascribed to x; in their absence the empty list acts as the second element of the returned list. In a case of False value on a test ascribed to a formal x argument, the procedure call Definition2[x] will be returned unevaluated. Analogously to the above procedures, the procedure Definition2 processes the main both the erroneous and especial situations.

Using the Definition2 procedure and the list representation, we give an example of a simple enough Info procedure whose call Info[x] in a convenient form returns the complete definition of a symbol x, including its usage. While the call Info[x, y] with the second optional y argument an indefinite symbol through it additionally returns the usage for x symbol in string format. The following fragment represents the source code of the Info procedure with examples of its typical application.

In[3221]:= Info[x_ /; SymbolQ[x], y___] :=

If[! HowAct[x], \$Failed, {If[StringQ[x::usage],

Print[If[{y} != {} && ! HowAct[y], y = x::usage, x::usage]],

Print["Usage on " <> ToString[x] <> " is absent"]],

ToExpression[Definition2[x][[1 ;–2]]]; Definition[x]}[[–1]]]

In[3222]:= Info[StrStr]

The call StrStr[x] returns an expression x in string format if x is different from string; otherwise, the double string obtained from an expression x is returned.

Out[3222]= StrStr[x_] := If[StringQ[x], "\"" <> x <> "\"",

ToString[x]]

In[3223]:= x[x_] := x; x[x_, y_] := x*y; x[x_, y_, z_] := x*y*z

In[3224]:= Info[x]

Usage on x is absent

Out[3224]= x[x_] := x

x[x_, y_] := x*y

x[x_, y_, z_] := x*y*z

In[3225]:= Info[StrStr, g47]

The call StrStr[x] returns an expression x in string format if x is different from string; otherwise, the double string obtained from an expression x is returned.

Out[3225]= StrStr[x_] := If[StringQ[x], "\"" <> x <> "\"", ToString[x]]

In[3226]:= g47

Out[3226]= "The call StrStr[x] returns an expression x in string format if x is different from the string; otherwise, the double string obtained from an expression x is returned."

In[3227]:= Info[agn]

Out[3227]= \$Failed

If the first x argument – an indefined symbol, the procedure call Info[x] returns \$Failed.

Another moment should be mentioned. In some cases, the above procedural objects can be represented in functional form based on the list structures of the format:

F[x_, …, z_] := {Save[w, a, b, c, …]; Clear[a, b, c, …];

Procedure body, Get[w]; DeleteFile[w]}[[–2]]

The Save function saves all values of local and global procedure variables in a certain w file, then clears all these variables, and then executes the procedure body. Finally, Get function loads the w file into the current session, restoring {a, b, c,...} variables, and then deletes the w file. The result of the function call of the type described is the second list element, beginning with its end in a case if the procedure returns the result of the call through the last sentence of its body, which is a fairly frequent case. We can use {;|,} as the list element separators, depending on need. Thus, on the basis of the above design it is possible to program functional equivalents of quite complex procedures. An example is the functional equivalent of the SubsDel procedure described in section 3.4.

In[77]:= SubsDel[S_ /; StringQ[S], x_ /; StringQ[x], y_ /; ListQ[y] &&

AllTrue[Map[StringQ, y], TrueQ] &&

Plus[Sequences[Map[StringLength, y]]] == Length[y],

p_ /; MemberQ[{–1, 1}, p]] := {Save["#\$#", {"b", "c", "d", "h", "k"}];

Clear[b, c, d, h, k]; {b, c = x, d, h = StringLength[S], k};

If[StringFreeQ[S, x], Return[S], b = StringPosition[S, x][[1]]];

For[k = If[p == 1, b[[2]] + 1, b[[1]] – 1], If[p == 1, k <= h, k >= 1],

If[p == 1, k++, k––], d = StringTake[S, {k, k}];

If[MemberQ[y, d] || If[p == 1, k == 1, k == h], Break[],

If[p == 1, c = c <> d, c = d <> c]; Continue[]]];

StringReplace[S, c –> ""], Get["#\$#"]; DeleteFile["#\$#"]}[[–2]]

In[78]:= SubsDel["12345avz6789", "avz", {"8", "5"}, 1]

Out[78]= "1234589"

A comparative analysis of both implementations confirms aforesaid.

It is well known [8-12,16], that the user package uploaded into the current session can contains tools x whose definitions obtained by means of the call Definition[x] aren't completely optimized, i.e. contain constructions of the kind j <> "x`" where j – a context from the system list \$Packages. We have created a number of tools [16] that solve various problems of processing unoptimized definitions of both individual means and means in the user packages located in files of {"m", "mx"} formats. So, the call DefFunc1[x] provides return of the optimized definition of an object x whose definition is located in the user package or nb–document and that has been loaded into the current session. At that, a name x should define an object without any attributes and options or with attributes and/or options. Fragment below represents source code of the DefFunc1 procedure along with an example of its application.

In[7]:= Definition[ListListQ]

Out[7]= ListListQ[Global`ListListQ`L_] :=

If[ListQ[Global`ListListQ`L] && Global`ListListQ`L != {} &&

Length[Global`ListListQ`L] >= 1 &&

Length[Select[Global`ListListQ`L, ListQ[#1] &&

Length[#1] == Length[Global`ListListQ`L[[1]]] &]] ==

Length[Global`ListListQ`L], True, False]

In[8]:= DefFunc1[x_ /; SymbolQ[x] || StringQ[x]] :=

Module[{a = GenRules[Map14[StringJoin, {"Global`",

Context[x]}, ToString[x] <> "`"], ""], b = Definition2[x][[1]]},

ToExpression[Map[StringReplace[#, a] &, b]]; Definition[x]]

In[9]:= DefFunc1[ListListQ]

Out[9]= ListListQ[L_] := If[ListQ[L] && L != {} &&

Length[L] >= 1 && Length[Select[L, ListQ[#1] &&

Length[#1] == Length[L[[1]]] &]] == Length[L], True, False]

So, the procedure call DefFunc1[x] in an optimized format returns the definition of an object x contained in a package or a notebook loaded into the current session. The object name is set in string format or symbol format depending on the object type (procedure, function, global variable, procedure variable, etc.). Thus, in the 2nd case the definition is essentially more readably, above all, for rather large source codes of procedures, functions, along

with other objects. The TypesTools procedure is rather useful.

Calling TypesTools[x] procedure returns the three-element list whose elements are sub-lists containing names in the string format of tools with context x in the terms of the objects such as Functions, Procedures, and Others, accordingly. During the procedure run, lists of the form {n, "Name"} are intermediately output, where n is the number of the tool being tested from the tools list with context x, and Name is the name of the tool being tested. The following fragment represents the source code of the TypesTools procedure, followed by its application.

In[3325]:= TypesTools[x_ /; ContextQ[x]] := Module[{a = {},

b = {}, c = {}, d = CNames[x], t, j}, Monitor[j = 1;

While[j <= Length[d], Pause[0.1]; t = d[[j]]; If[QFunction[t],

AppendTo[a, t], If[ProcQ[t], AppendTo[b, t], AppendTo[c, t]]];

j++], {j, t}]; {a, b, c}]

{1, "AcNb"}

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

{1416, "\$Version2"}

Out[3326]:= {{"AcNb", "ActBFM", …, "XOR1"},

{"ActCsProcFunc", …, "\$SysContextsInM1"},

Calling ContextMonitor[x] procedure during its execution outputs the lists of the form {n, N, Tp, PI} where n is the number of the tool being tested from the tools list with context x, N – is the name of the tool being tested, Tp – its type {Function, Block, Module, Other} and PI a progress indicator; returning nothing. The source code of the procedure is represented below.

ContextMonitor[x_/; ContextQ[x]] := Module[{c, d = CNames[x], t, j}, Monitor[c = 0; Map[{t = #, c++, j = TypeBFM[#], Pause[0.5]} &, d], {c, t, If[! MemberQ[{"Block", "Function", "Module"}, j], "Other", j], ProgressIndicator[c, {1, Length[d]}]}];]

TypesTools & ContextMonitor procedures use the Monitor function whose call Monitor[x,y] generates a temporary monitor place in which the continually updated current y value will be displayed during the course of evaluation of x. Such approach may be a rather useful in many rather important applications.

2.2. Headings of procedures in Mathematica software

Procedures in Mathematica system are formally presented by Modules and Blocks whose program structure begins with a Heading, i.e. heading the header part of a procedure definition, preceded to the sign {:= | =} of the delayed, as a rule, or instant assignment. The components of the heading are the procedure name and its formal arguments with patterns "_", possibly also with testing functions assigned to them.

It is necessary to highlight that in Mathematica system as correct procedural objects {Block, Module} only those objects are considered which contain the patterns of the formal arguments located in a certain order, namely:

1. The coherent group of formal arguments with patterns "_" has to be located at the very beginning of the tuple of formal arguments in headings of the above procedural objects;

2. Formal arguments with patterns "__" or "___" can to finish the tuple of formal arguments; at that, couples of adjacent arguments with patterns consisting from {"__", "___"} are inadmissible because of possible violation of correctness (in context of scheduled computing algorithm) of calls of the above procedural objects as a simple enough fragment illustrates:

In[1221]:= A[x_, y__, z__] := x*y^2*z^3

In[1222]:= {A[x, y, z], A[x, y, h, z], A[x, y, h, x, a, b]}

Out[1222]= {x*y^2*z^3, h^z^3*x*y^2, h^x^a^b^3*x*y^2}

In[1223]:= G[x_, y__, z___] := x + y + z

In[1224]:= {G[x, y, z], G[x, y, m, n, z], G[x, y, z, h]}

Out[1224]= {x + y + z, m + n + x + y + z, h + x + y + z}

Other rather simple examples illustrate told. Thus, the real correctness of tuple of formal arguments can be coordinated to their arrangement in the tuple in context of patterns {“_”, “__”, “___”}. At the same time, for all patterns for formal arguments the testing Testx function of a rather complex kind can be used as the following evident fragment illustrates:

In[1567]:= Sg[x_ /; StringQ[x], y__ /; If[Length[{y}] == 1,

IntegerQ[y], MemberQ3[{Integer, List, String},

In[1568]:= Sg["agn", 72, 77, "sv", {a, b}]

Out[1568]= {"agn", 72, 77, "sv", {a, b}}

In[1569]:= Sg1[x_ /; StringQ[x], y___ /; If[{y} == {}, True,

If[Length[{y}] == 1, IntegerQ[y], MemberQ3[{List, String,

Integer}, Map[Head, {y}]]]]] := {x, y}

In[1570]:= Sg1["agn", 72, 77, "sv", {a, b}, a + b]

Out[1570]= Sg1["agn", 72, 77, "sv", {a, b}, a + b]

Furthermore, a procedure and function headings in testing functions are allowed to use procedure and function definitions (using the list structure) that are activated in the current session at the time the objects containing them are called, for example:

In[1620]:= M1[x_ /; {SetDelayed[h[a_], Module[{}, 42*a]],

h[x] < 2020}[[2]], y_] := Module[{a=5, b=7}, a*x^2 + b*y^2]

In[1621]:= M1[42, 47]

Out[1621]= 24283

In[1622]:= Definition[h]

Out[1622]= h[a_] := Module[{}, 42*a]

Right there once again it should be noted one an essential moment. Definition of the testing Testx function can be directly included to the procedure or function heading, becoming active in the current session by the first procedure or function call:

In[2]:= P[x_, y_ /; {IntOddQ[t_] := IntegerQ[t] && OddQ[t],

IntOddQ[y]}[[1]]] := x*y

In[3]:= P[72, 77]

Out[3]= 5544

In[4]:= Definition[IntOddQ]

Out[4]= IntOddQ[t_] := IntegerQ[t] && OddQ[t]

In[5]:= t = 77; Save["#", t]

In[6]:= P[x_ /; Module[{}, If[x^2 < Read["#"], Close["#"];

True, Close["#"]; False]], y_] := x*y

In[7]:= P[8, 7]

Out[7]= 56

Generally speaking, Mathematica's syntax and semantics, when defining procedures (modules and blocks), allow the use of procedure definitions in both the definition of test functions for formal arguments and the definitions of local variables, as the following fairly simple fragment illustrates quite clearly, while for classical functions similar assumptions are only possible for test functions, of course.

In[9]:= Avz[x_ /; If[SetDelayed[g[t_], Module[{a = 42}, t^2 + a]];

g[x] < 777, True, False]] := Module[{a = SetDelayed[v[t_],

Module[{b = 47, c = 67}, b*t^3 + c]]}, a = 77; a*v[x]]

In[10]:= Avz[7]

Out[10]= 1246476

In[11]:= Avz[100]

Out[11]= Avz[100]

In[12]:= Definition[g]

Out[12]= g[t_] := Module[{a = 42}, t^2 + a]

In[13]:= Definition[v]

Out[13]= v[t_] := Module[{b = 47, c = 67}, b*t^3 + c]

In[14]:= Context[g]

In[15]:= Context[v]

Out[15]= "Global`"

In[16]:= \$Context

Out[16]= "Global`"

In[17]:= Contexts[]

In[18]:= Length[%]

Out[18]= 1611

The procedures whose definitions are contained in the test functions or in the local variables domain are activated in the current session when the procedure contains them is called. In addition, the symbol v defined in the local area has the current context, while the symbol g defined in the test function obtains the context being the first in the list Contexts[] of all contexts of the current session. The feasibility of using the above approach to defining procedures is discussed in some detail in [8,11,15].

In a number of tasks, substantially including debugging of the user software, there is a necessity of dynamic change of the testing functions for formal arguments of blocks, functions and modules in the moment of their call. The ChangeLc procedure allowing dynamically monitoring influence of testing functions of formal arguments of tools for correctness of their calls is for this purpose programmed. The following fragment submits the source code of the procedure with examples of its application.

In[4478]:= ChangeLc[x_ /; StringQ[x] || ListQ[x],

P_ /; BlockFuncModQ[P], y___] :=

Module[{a = ArgsBFM2[P], b = Definition1[P],

p, c, d, g, n, m = Flatten[{x}], t = ToString[P]},

p = Map[StringTake[#, Flatten[StringPosition[#, "_"]][[1]]] &, m];

b = StringReplace[b, "Global`" <> t <> "`" > ""];

c = StringReplace[b, t <> "[" > ToString[n] <> "[", 1];

a = Select[a, SuffPref[#, p, 1] &];

If[a == {}, P @@ {y},

c = StringReplace[c, Rule1[Riffle[a, m]], 1];

ToExpression[c]; t = n @@ {y};

{If[SuffPref[ToString1[t], ToString[n] <> "[", 1],

"Updating testing functions for formal arguments of " <>

ToString[P] <> " is unsuitable", t], Remove[n]}[[1]]]]

In[4479]:= G[x_, y_, z_Integer] := x^2 + y^2 + z^2

In[4480]:= ChangeLc["y_ /;IntegerQ[y]", G, 42, 47, 67]

Out[4480]= 8462

In[4481]:= ChangeLc["y_ /;RationalQ[y]", G, 42, 47, 67]

Out[4481]= "Updating testing functions for formal

arguments of G is unsuitable"

In[4482]:= ChangeLc["y_ /;RationalQ[y]", G, 42, 47/72, 67]

Out[4482]= 32417761/5184

The procedure call ChangeLc[x, P, y] returns the result of a call P[y] on condition of replacement of the testing functions of arguments of a block, module or function P by the new functions determined by a string equivalent x or by their list. The string equivalent is coded in shape "x_ /; TestQ[x]", x – an argument.

The task of checking formal arguments of blocks, modules, functions for their validity to admissible values plays a rather important role and this problem is solved by means of the test functions assigned to the corresponding formal arguments of the above objects. The first part of the next fragment represents an example of how to organize a system to test the actual values obtained when the Art procedure is called. At that, if the formal arguments receive invalid actual values, then procedure call is returned unevaluated with the corresponding message printing for the first of such formal arguments. Note that built-in means Mathematica also do quite so. Meantime, the task of checking all invalid values for formal arguments when calling the above objects is more relevant. Below is a possible approach to that.

In[2185]:= Art[x_ /; If[IntegerQ[x], True,

Print["Argument x is not integer, but received: x = " <>

ToString1[x]]; False],

y_ /; If[ListQ[y], True,

Print["Argument y is not a list, but received: y = " <>

ToString1[y]]; False],

z_ /; If[StringQ[z], True,

Print["Argument z is not a string, but received: z = " <>

ToString1[z]]; False]] :=

Module[{a = 77}, N[x*(Length[y] + StringLength[z])/a]]

In[2186]:= Art[47, {a, b, c}, "RansIan"]

Out[2186]= 6.1039

In[2187]:= Art[47.42, 67, "abc"]

Argument x is not integer, but received: x = 47.42

Out[2187]= Art[47.42, 67, "abc"]

In[2188]:= Art[47.42, 67, "abc"]

Argument x is not integer, but received: x = 47.42

Out[2188]= Art[47.42, 67, "abc"]

In[2189]:= Art[500, 67, "abc"]

Argument y is not a list, but received: y = 67

Out[2189]= Art[500, 67, "abc"]

In[2190]:= Art[500, {a, b, c}, 77]

Argument z is not a string, but received: z = 77

Out[2190]= Art[500, {a, b, c}, 77]

The above approach is based on the following construction:

G[x_ /; If[Testx, \$x\$ = True, Print[]; \$x\$ = False; True],

y_ /; If[Testy, \$y\$ = True, Print[]; \$y\$ = False; True], …

h_ /; AllTrue[{\$x\$, \$y\$, }, # == True &]] := Module[{}, ]

The Kr procedure is an example of using of the above approach.

In[2192]:= Kr[x_ /; If[IntegerQ[x], \$x\$ = True,

Print["Argument x is not integer, but received: x = " <>

ToString1[x]]; \$x\$ = False; True],

y_ /; If[ListQ[y], \$y\$ = True,

Print["Argument y is not a list, but received: y = " <>

ToString1[y]]; \$y\$ = False; True],

z_ /; If[StringQ[z], \$z\$ = True,

Print["Argument z is not a string, but received: z = " <>

ToString1[z]]; \$z\$ = False; True],

h_ /; AllTrue[{\$x\$, \$y\$, \$z\$}, # == True &]] :=

Module[{a = 77}, N[x*(Length[y] + StringLength[z])/a]]

In[2193]:= Kr[47, {a, b, c}, "RansIan", 78]

Out[2193]= 6.1039

In[2194]:= Kr[42.47, 67, "abc", 78]

Argument x is not integer, but received: x = 42.47

Argument y is not a list, but received: y = 67

Out[2194]= Kr[42.47, 67, "abc", agn]

In[2195]:= Kr[42.47, 67, 90, 78]

Argument x is not integer, but received: x = 42.47

Argument y is not a list, but received: y = 67

Argument z is not a string, but received: z = 90

Out[2195]= Kr[42.47, 67, 90, agn]

The final part of the above fragment represents the Kr procedure equipped with a system for testing the values of the actual arguments passed to the formal arguments when the procedure is called. At that, only three {x, y, z} arguments are used as the formal arguments used by the procedure body, whereas the 4th additional argument h, when the procedure is called obtains an arbitrary expression, and in the Kr body is not used. Argument h at the procedure header level tests the validity of the actual values obtained by formal arguments when the procedure is called. The argument allows to obtain information on all inadmissible values for formal arguments at the procedure call. The fragment is fairly transparent and does not require any clarifying.

Based on the form of the heading shown above, it is possible to represent its rather useful extension, that allows to form the function body at the level of such heading. In general, the format of such header takes the following form:

G[x_ /; If[Test[x], Save["#", a, b, c, ]; a = {x, True}; True,

Save["#", a, b, c, ]; Print["Argument x is not integer, but received:

x = " <> ToString1[x]]; a = {x, False}; True],

y_ /; If[Test[y], b = {y, True}; True,

Print["Argument y is not integer, but received:

y = " <> ToString1[y]]; b = {y, False}; True],

z_ /; If[Test[z], c = {z, True}; True,

Print["Argument z is not integer, but received:

z = " <> ToString1[z]]; c = {z, False}; True],

………………………………………………………………………

h_ /; If[AllTrue[{a[[2]],b[[2]], c[[2]]}, # == True &],

Result = Function_Body[a[[1]], b[[1]], c[[1]]]; Get["#"];

DeleteFile["#"]; True, Get["#"]; DeleteFile["#"]; False]] := Result

where Test[g] – a testing expression, testing an expression g on admissibility to be g as a valid value for the g argument and Result is the result of Function_body evaluation on formal arguments {x,y,z,…}. Let give a concrete filling of the above structural form as an example:

In[3338]:= ArtKr[x_ /; If[IntegerQ[x], Save["#", a, b, c];

a = {x, True}; True, Save["#", a, b, c];

Print["Argument x is not Integer, but received:

x = " <> ToString1[x]]; a = {x, False}; True],

y_ /; If[RealQ[y], b = {y, True}; True,

Print["Argument y is not Real, but received:

y = " <> ToString1[y]]; b = {y, False}; True],

z_ /; If[RationalQ[z], c = {z, True}; True,

Print["Argument z is not Rational, but received:

z = " <> ToString1[z]]; c = {z, False}; True],

h_ /; If[AllTrue[{a[[2]], b[[2]], c[[2]]}, # == True &],

\$Result\$ = N[a[[1]]*b[[1]]*c[[1]]]; Get["#"]; DeleteFile["#"]; True,

Get["#"]; DeleteFile["#"]; False]] := \$Result\$

In[3339]:= \$Result\$ = ArtKr[72, 77.8, 50/9, vsv]

Out[3339]= 31120.

In[3340]:= \$Result\$ =ArtKr[72, 77.8, 78, vsv]

Argument z is not Rational, but received: z = 78

Out[3340]= ArtKr[72, 77.8, 78, vsv]

In[3341]:= ArtKr[72, 778, 78, vsv]

Argument y is not Real, but received: y = 778

Argument z is not Rational, but received: z = 78

Out[3341]= ArtKr[72, 778, 78, vsv]

In[3342]:= ArtKr[7.2, 77.8, 78, vsv]

Argument x is not Integer, but received: x = 7.2

Argument z is not Rational, but received: z = 78

Out[3342]= ArtKr[7.2, 77.8, 78, vsv]

In[3343]:= ArtKr[7.2, 900, 50, vsv]

Argument x is not Integer, but received: x = 7.2

Argument y is not Real, but received: y = 900

Argument z is not Rational, but received: z = 50

Out[3343]= ArtKr[7.2, 900, 50, vsv]

The function call ArtKr[x, y, z, h] returns the result of evaluation of a Function_Body on actual arguments {x, y, z}. In addition, the call ArtKr[x, y, z, h] as a value for formal h argument obtains an arbitrary expression. Through the global variable \$Result\$, the call ArtKr[x, y, z, h] additionally returns the same value. At that, the above structural form is based on the processing principle of actual arguments passed to an object (block, function, module), namely the values of actual arguments are processed by the corresponding testing functions from left to right until the first calculation False that is obtained by a testing function, after that the call of the object is returned as unevaluated, otherwise the result of the object calculation is returned.

Therefore, the test functions for the leading formal arguments of the form are formed in such way that they return True when fixing the real value of the test functions and the values passed to them. Whereas the test function for the auxiliary argument h determines both the evaluation of the object body and validity of the factual values for the principal arguments {x, y, z}, solving the task of returning the result of the calculation of the body of the object or returns the result of the call unevaluated. Fragment above is fairly transparent and does not require any clarifying.

According to the scheme described above, Mathematica allows a number of useful modifications. In particular, the following form of organizing headers {block, function, module} having the following format may well be of interest:

S[x_ /; {X1; …; Xp; {Testx|True}}[[1]],

y_ /; {Y1; … ; Yn; Testy}[[1]],

………………………………………………………..

z___ /; {Z1; …; Zt; Testz}[[1]] := Object

In addition as {X1,…,Xp; Y1,…,Yn; ...; Z1,…,Zt} act admissible offers of the Mathematica language, including calls of blocks, functions and modules whereas as {Testx,Testy,…,Testz} act the testing functions ascribed to the corresponding formal {x,y,…,z} arguments. In a case if there is no the test function for a formal argument (i.e. argument allows any type of actual value) instead of it is used True. Moreover, the test function for pattern "x___" or "x__" should refer to all formal arguments relating thereto. In a case of such patterns used in an object header should be used or True, or a special test function, for example, that is presented below. In a number of cases similar approach can be interesting enough. The procedure call TrueListQ[x, y] returns True if a list x has elements whose types match to the corresponding elements of a list y, otherwise False is returned. If lengths of both lists are different, then the first Min[x, y] their elements are analyzed. At that, the call with the third argument z – an indefinite symbol additionally returns the list of elements positions of list x whose types different from the corresponding types from the y list. The source code of the TrueListQ procedure is represented below.

In[942]:= TrueListQ[x_ /; ListQ[x], y_ /; ListQ[y], z___] :=

Module[{a = Length[x], b = Length[y], c = {}, t = {}},

AppendTo[t, j]; AppendTo[c, False]], {j, Min[a, b]}];

If[{z} != {} && SymbolQ[z], z = t; If[t == {}, True, False],

If[t == {}, True, False]]]

In[943]:= TrueListQ[{77, 6, "abc"}, {Integer, Symbol, String}]

Out[943]= False

In[944]:= TrueListQ[{77, 7.8, "a"}, {Integer, Real, String}]

Out[944]= True

In[945]:= {TrueListQ[{a, 78, "2020"}, {Integer, Real, String}, g], g}

Out[945]= {False, {1, 2}}

The following simple GW procedure uses the TrueListQ in heading for definition of its optional formal y argument along with illustrative examples of the procedure calls.

In[63]:= GW[x_, y___ /; TrueListQ[{y}, {Integer, Real, Rational},

agn]] := Module[{a = 78}, x*(y + a)]

In[64]:= GW[77]

Out[64]= 6006

In[65]:= GW[77, 78, 7.8, 7/8]

Out[65]= 12680.

In[66]:= {GW[77, 78, 42, 47], agn}

Out[66]= {GW[77, 78, 42, 47], {2, 3}}

As some instructive information, an example of a procedure whose heading is based on the principles mentioned above is presented. The procedure call Mn[x, y, z] returns the list of all arguments passed to the procedure without reference to them.

In[3349]:= Mn[x_ /; {WriteLine["#", x]; IntegerQ[x]}[[1]],

y_ /; {WriteLine["#", y]; ListQ[y]}[[1]],

z___ /; {WriteLine["#", z]; True}[[1]]] :=

Module[{Arg}, Close["#"]; Arg = ReadString["#"]; DeleteFile["#"];

Arg = StringReplace[Arg, "\n" –> ","];

Arg = StringTake[Arg, {1, –2}];

Arg = ToExpression[StringToList[Arg]]; Arg]

In[3350]:= Mn[77, {42, 47, 67}]

Out[3350]= {77, {42, 47, 67}}

In[3351]:= Mn[77, {42, 47, 67}, a + b]

Out[3351]= {77, {42, 47, 67}, a + b}

In[3352]:= Mn[m, {42, 47, 67}, a + b]

Out[3352]= Mn[m, {42, 47, 67}, a + b]

In[3353]:= Mn[m, {42, 47, 67}, a + b, 77, 78]

Out[3353]= Mn[m, {42, 47, 67}, a + b, 77, 78]

Another point should be emphasized. As already mentioned, when calling an object (block, function or module), the factual arguments passed to it in its heading are processed in the list order, i.e., from left to right in the list of formal arguments. In this regard, and in view of the foregoing, there is a rather real possibility of setting in definition of some formal argument of a test function that can be used as test functions for subsequent formal arguments of the object heading. The following fragment represents a rather simple Av function whose heading contains definitions of two Boolean functions, used by a testing function for the last formal z argument of the Av function. At the same time, when you call function Av, both Boolean functions B and V become active in the current session, as it is well shown in the examples below.

In[3442]:= Av[x_ /; {SetDelayed[B[t_], If[t <= 90, True, False]];

NumberQ[x]}[[1]],

y_ /; {SetDelayed[V[t_], ! RealQ[t]]; RealQ[y]}[[1]],

z_ /; B[z] && V[z]||RationalQ[z]] := N[Sqrt[x*y/z]]

In[3443]:= {Av[77, 7.8`, 42/47], Av[77, 90, 500]}

Out[3443]= {25.9249, Av[77, 90, 500]}

In[3444]:= Definition[B]

Out[3444]= B[t_] := If[t <= 90, True, False]

In[3445]:= Definition[V]

Out[3445]= V[t_] := ! RealQ[t]

In[3446]:= {B[42], V[47]}

Out[3446]= {True, True}

In[3447]:= Ag[x_ /; {SetDelayed[W[t_], Module[{a = 77}, a*t^2]];

IntegerQ[x]}[[1]]] := W[x] + x^2

In[3448]:= {Ag[42], W[42]}

Out[3448]= {137592, 135828}

In[3449]:= Definition[W]

Out[3449]= W[t_] := Module[{a = 77}, a*t^2]

Thus, in particular, the last example of the previous fragment also shows that the object W (block, function, module) defined in the header of another Ag object allows a correct call in the body of the Ag object yet when it is first called. When Ag is called, W becomes active in the current session. The above fragments are quite transparent and do not require any clarifying. Technique, presented in them are of some practical interest in programming of the objects headings and objects as a whole.

On the assumption of the general definition of a procedure, in particular, of modular type

M[x_ /; Testx, y_ /; Testy, ...] := Module[{Locals}, Procedure body]

and of the fact that concrete definition of procedure is identified not by its name, but its heading we will consider a set of useful enough tools [16] that provide the various manipulations with the headings of procedures and functions and play a important part in the procedural and functional programming and, above all, of programming of problems of the system character.

In particular, the possibilities of the HeadingQ ÷ HeadingQ3 procedures are overlapped by opportunities of the means whose call TestHeadingQ returns True if a x represents the heading in

string format of a block, module, function, and False otherwise. Whereas the procedure call TestHeadingQ[x, y] with the second optional y argument an indefinite variable thru it additionally returns information specifying the reasons of the incorrectness of a heading x. At that, on x objects of the same name (multiple objects) the procedure call returns \$Failed; the extension of the procedure to case of the multiple objects does not cause much difficulty. The source code of the TestHeadingQ procedure and the comparative analysis of its use concerning the HeadingQ ÷ HeadingQ3 tools say about its preference at programming in Mathematica [8,9,15]. So, of the detailed analysis follows, that the TestHeadingQ procedure on the opportunities surpasses the above testing tools of the same purpose.

In the light of real correctness of formal arguments that has been defined above and is caused by mutual arrangements of formal arguments in the context of patterns {"_", "__", "___"} we can significantly generalize the above group of procedures HeadingQ ÷ HeadingQ3, intended for testing of correctness of headings of the user blocks, functions & modules, additionally using the CorrTupleArgs procedure. For this purpose the tool HeadingsUQ can be used.

Calling the HeadingsUQ[x] procedure returns True if all components composing an object x in the context of the call Definition[x] have correct headings, and False otherwise. While the call HeadingsUQ[x, y] in addition through the 2nd optional argument an undefined y symbol returns the list the elements of which are True if the heading of the appropriate component of x object is correct, or the list whose first element determines incorrect heading of a component of the x object, whereas the second element determines of the component number with this heading concerning the call Definition[x]. The source code of the TestHeadingQ procedure with examples of its use can be found in [15,16]. The HeadingsUQ procedure rather exhaustively tests the correctness of the headings of blocks, functions and modules.

It is appropriate to make one quite substantial remark here. As you know, Mathematica does not allow to use the testing functions in block, function, and module headers that will use factual argument values that relate to other formal arguments as the following simple fragment rather visually illustrates.

In[7]:= V[x_ /; IntegerQ[x], y_ /; EvenQ[x] && IntegerQ[y]] := x/y

In[8]:= V[42, 77]

Out[8]= V[42, 77]

In the example shown, the testing function assigned to the second formal argument y cannot include the value passed to the first formal argument x, otherwise by causing the return of V function call unevaluated. We will offer here one interesting reception, allowing to solve similar and some other problems. Consider it with a rather simple example.

In[2296]:= V[x_ /; {Save3["j", x], IntegerQ[x]}[[–1]],

y_ /; {If[Get["j"]*y > 100, True, False], DeleteFile["j"]}[[1]]] := x*y

In[2297]:= V[42, 77]

Out[2297]= 3234

In[2298]:= V[7, 8]

Out[2298]= V[7, 8]

In order to pass an actual value (passed to the x argument when the V function is called) to a testing function of another y argument, by the function Save3 the value is stored in a сertain temporary j file. Then call Get[j] allows to read the stored value from the file j in the required point of the testing function of any formal argument of the header, after necessity deleting file j. To solve such problems, a Save3 function is of interest a version of the built-in Save function whose Save3[f, x] call saves in the f of the txtformat an expression x without returning anything.

In[2310]:= Save3[f_, x_] := {Write[f, x], Close[f]}[[1]]

In[2311]:= Save3["###", b*S + c*V + G*x]

In[2312]:= Get["##"]

Out[2312]= b*S + c*V + G*x

After calling Save3[f, x], the file with expression x remains closed and is loaded into the current session by function Get[f], returning the x value. Note that the Write function used by the Save3 has a number of features discussed in detail in [8]. In the first place, this refers to preserving the sequence of expressions.

The following procedure serves as an useful enough tool at manipulating with functions and procedures, its call HeadPF[x] returns heading in string format of a block, module or function with a x name activated in the current session, i.e. the function in its traditional understanding with heading. Whereas on other values of the x argument the call is returned unevaluated. At the same time, the problem of definition of headings is actual also in a case of the objects of the above type of the same name which have more than one heading. In this case the procedure call HeadPF[w] returns the list of headings in string format of the subobjects composing a w object as a whole. The following fragment represents the source code of the HeadPF procedure along with a typical example of its application.

In[2225]:= M[x_ /; x == "avzagn"] := Module[{a}, a*x];

M[x_, y_, z_] := x*y*z; M[x_String] := x;

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

M[x_, y_] := Module[{a, b, c}, "abc"; x + y]

In[2226]:= HeadPF[x_ /; BlockFuncModQ[x]] := Module[{b,

c = ToString[x], a = Select[Flatten[{PureDefinition[x]}],

! SuffPref[#, "Default[", 1] &]}, b = Map[StringTake[#,

{1, Flatten[StringPosition[#, {" := ", " = "}]][[1]] – 1}] &, a];

If[Length[b] == 1, b[[1]], b]]

Out[2227]= {"M[x_ /; x == \"avzagn\"]", "M[x_, y_, z_]",

"M[x_ /; IntegerQ[x], y_String]", "M[x_String]", "M[x_, y_]"}

Here, it is necessary to make one essential enough remark concerning the means dealing with the headings of procedures and functions. The matter is that as it was shown earlier, the testing tools ascribed to the formal arguments, as a rule, consist of the earlier defined testing functions or the reserved keywords defining the type, for example, Integer. While as a side effect the builtin Mathlanguage allows to use the constructions that can contain definitions of the testing tools, directly in the headings of procedures and functions. Certain interesting examples of that have been represented above. Meanwhile, despite of such opportunity, 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 the procedures and functions. For this reason, HeadPF procedure presented above in such cases can return incorrect results. Whereas the HeadPFU procedure covers such peculiar cases. The procedure call HeadPFU[x] correctly returns the heading in string format of a block, module or function with a name x activated in the current session regardless of a way of definition of testing of factual arguments. The fragment below presents the source code of the HeadPFU procedure along with typical examples of its application.

In[2230]:= P[x_, y_ /; {IntOddQ[t_] := IntegerQ[t] && OddQ[t],

IntOddQ[y]}[[–1]]] := x*y

Out[2231]= "P[x_, y_ /; {IntOddQ[t_]"

Module[{a = Flatten[{PureDefinition[x]}], b = {}, c, g},

Do[c = Map[#[[1]] – 1 &, StringPosition[a[[j]], " := "]];

Do[If[SyntaxQ[Set[g, StringTake[a[[j]], {1, c[[k]]}]]],

AppendTo[b, g]; Break[], Null], {k, Length[c]}], {j, Length[a]}];

If[Length[b] == 1, b[[1]], b]]

Out[2233]= "P[x_, y_ /; {IntOddQ[t_] := IntegerQ[t] && OddQ[t],

IntOddQ[y]}[[–1]]]"

In[2234]:= V[x_ /; {Save3["#", x], IntegerQ[x]}[[–1]],

y_ /; {If[Get["#"]*y > 77, True, False], DeleteFile["#"]}[[1]]] := x*y

Out[2235]= "V[x_ /; {Save3[\"#\", x], IntegerQ[x]}[[–1]],

y_ /; {If[Get[\"#\"]*y > 77, True, False], DeleteFile[\"#\"]}[[1]]]"

In this regard the testing of a x object regarding to be of the same name is enough actually; the QmultiplePF procedure [16] solves the problem whose call QmultiplePF[x] returns True, if x is an object of the same name (Function, Block, Module), and False otherwise. Whereas the procedure call QmultiplePF[x, y] with the second optional y argument an indefinite variable through y returns the list of definitions of all subobjects with a name x.

Right there pertinently to note some more tools linked with

In[2310]:= HeadingsPF[x___ /; SameQ[x, {}]] := Module[{a = {},

d = {}, k = 1, b, c = {{"Block"}, {"Function"}, {"Module"}}, t},

Map[If[Quiet[Check[BlockFuncModQ[#], False]],

AppendTo[a, #], Null] &, Names["`*"]];

b = Map[Headings[#] &, a]; While[k <= Length[b], t = b[[k]];

If[NestListQ[t], d = Join[d, t], AppendTo[d, t]]; k++];

Map[If[#[[1]] == "Block", c[[1]] = Join[c[[1]], #[[2 ;1]]],

If[#[[1]] == "Function", c[[2]] = Join[c[[2]], #[[2 ;1]]],

c[[3]] = Join[c[[3]], #[[2 ;1]]]]] &, d];

c = Select[c, Length[#] > 1 &]; If[Length[c] == 1, c[[1]], c]]

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

L1[x_] := x; M[x_, y_, z_] := x + y + z; L[x_, y_] := x + 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}; F[x_ /; x == "avz"] := x

Out[2312]= {{"Block", "M[x_ /; ListQ[x], y_]"},

{"Function", "F[x_ /; x === \"avz\", y_]", "F[x_ /; x == \"avz\"]",

"L[x_, y_]", "L1[x_]", "M[x_, y_, z_]", "M[x_String]"},

{"Module", "M[x_ /; x === \"avz\", y_]", "M[x_, y_]",

"M[x_ /; x == \"avz\"]", "M[x_ /; IntegerQ[x], y_String]"}}

In the light of possibility of existence in the current session of procedures and functions of the same name with different headings the problem of removal from the session of an object with the concrete heading is of a certain interest; this problem is solved by the procedure RemProcOnHead, whose the source code with an example of its application is represented below.

ListQ[x] && AllTrue[Map[HeadingQ[#] &, x], TrueQ]] :=

Module[{b, c, d, p, a = HeadName[If[ListQ[x], x[[1]], x]]},

If[! MemberQ[Names["`*"] || ! HowAct[a], a], \$Failed,

b = Definition2[a]; c = b[[1 ;2]]; d = b[[1]];

ToExpression["ClearAttributes["<>a<> ","<>ToString[d]<>"]"];

p = Select[c, ! SuffPref[#, x, 1] &];

ToExpression["Clear[" <> a <> "]"];

If[p == {}, "Done", ToExpression[p];

ToExpression["SetAttributes["<>a <> "," <> ToString[d] <> "]"];

"Done"]]]

In[8]:= V[x_] := Module[{}, x^6]; V[x_Integer] := x^2

Out[9]= {"Done", "Done"}

In[10]:= Definition[V]

Out[10]= Null

The call RemProcOnHead[x] returns "Done" with removing from the current session a procedure, function or their list with heading or with list of x headings that are given in string format; headings in call RemProcOnHead[x] is coded according to the format ToString1[x].

The task, closely adjacent to the headings, is to determine the arity of objects. For this purpose, we have created a number of means [8,9]. In particular, the ArityBFM1 procedure defining arity of objects of the type {module, classical function, block} serves as quite useful addition to the procedure Arity and some others.

The procedure call ArityBFM1[x] returns the arity (number of the formal arguments) of a block, function or module x in the format of 4element list whose the 1st, the 2nd, the 3rd elements define quantity of formal arguments with the patterns "_", "__" and "___" accordingly. While the 4th element defines common quantity of formal arguments which can be different from the quantity of actual arguments. In addition, the x heading should has classical type, i.e. it should not include nonstandard, but acceptable methods of headings definition. The unsuccessful procedure call returns \$Failed.

The following procedure serves for definition of arity of system functions. The procedure call AritySystemFunction[x] returns the 2–element list whose 1st element defines number of formal arguments, while the second element quantity of admissible actual arguments. The call with the second optional y argument an indefinite variable thru it returns the generalized template of formal arguments.

In[3341]:= AritySystemFunction[x_, y___] := Module[{a, b, c, d, g, p},

If[! SysFunctionQ[x], \$Failed, a = SyntaxInformation[x];

If[a == {}, \$Failed, c = {0, 0, 0, 0}; b = Map[ToString, a[[1]][[2]]];

b = Map[If[SuffPref[#, "{", 1], "_",

If[SuffPref[#, {"Optional", "OptionsPattern"}, 1], "_.", #]] &, b];

If[{y} != {} && ! HowAct[y],

y = Map[ToExpression[ToString[Unique["x"]] <> #] &, b], 77];

Map[If[# == "_", c[[1]]++, If[# == "_.", c[[2]]++,

If[# == "__", c[[3]]++, c[[4]]++]]] &, b]; {p, c, d, g} = c;

d = DeleteDuplicates[{p + d, If[d != 0||g != 0, Infinity, p + c]}];

If[d != {0, Infinity}, d, Quiet[x[Null]]; If[Set[p, Messages[x]] == {}, d,

p = Select[Map[ToString, Map[Part[#, 2] &, p]],

! StringFreeQ[#, " expected"] &]; p = Map[StringTake[#,

{Flatten[StringPosition[#, ";"]][[1]] + 1, –2}] &, p];

p = ToExpression[Flatten[StringCases[p, DigitCharacter ..]]];

If[p == {}, {1}, If[Length[p] > 1, {Min[p], Max[p]}, p]]]]]]]

In[3342]:= {AritySystemFunction[If, g72], g72}

Out[3342]= {{2, 4}, {x16_, x17_, x18_., x19_.}}

2.3. Optional arguments of procedures and functions

When programming procedures and functions often there is an expediency to define some of their formal arguments as optional. In addition, in case of explicit lack of such arguments by a call of tools, they receive values by default. System builtin Mathematica functions use two basic methods for dealing with optional arguments that are suitable for the user tools too. The first method consists in that that a value of each argument x that is coded by pattern "_:" in the form x_:b should be replaced by b, if the argument omitted. Almost all builtin system functions that use this method, omit arguments since the end of the list of formal arguments. So, simple function G[x_: 5, y_: 7] := {x, y} two optional arguments have, for which values by default – 5 and 7 respectively. As Mathematica system assumes that arguments are omitted since end of the list of formal arguments then we have not a possibility by positionally (in general selectively) do an argument as optional.

In[3376]:= G[x_: 5, y_: 6] := {x, y}

In[3377]:= {G[], G[42, 77], G[42]}

Out[3377]= {{5, 6}, {42, 77}, {42, 6}}

So, from a simple example follows that for function G from two optional arguments the call G[42] refers value by default to the second argument, but not to the first. Therefore this method has a rather limited field of application.

The second method of organization of optional arguments consists in use of explicit names for the optional arguments by allowing to give them values using transformation rules. This method is particularly convenient for means like Plot function which have a rather large number of optional arguments, only a few of which usually need to be set in a particular example. The typical method is that values for socalled named optional arguments can be specified by including the appropriate rules at the end of the arguments at a function call. At determining of the named optional arguments for a procedure or function g, it is conventional to store the default values for these arguments as a list of transformation rules assigned to Options[g]. So, as a typical example of definition for a tool with zero or more named optional arguments can be:

g[x_, y_, OptionsPattern[]] := Module[{}, x*y]

Then for this means a list of transformation rules assigned to Options[g] is determined

Options[g] = {val1 > a, val2 > b}

Whereas expression OptionValue[w] for a named optional argument w has to be included to the body of the tool, in order that this mechanism worked. Below is presented the definition of a function g that allows up to 2 named optional arguments:

In[2114]:= g[x_, y_, OptionsPattern[]] :=

(OptionValue[val1]*x + OptionValue[val2]*y)/

(OptionValue[val1]*OptionValue[val2])

In[2115]:= Options[g] = {val1 > 42, val2 > 47}

Out[2115]= {val1 > 42, val2 > 47}

In[2116]:= g[90, 500]

Out[2116]= 13640/987

In[2117]:= g[90, 500, val1 > 77]

Out[2117]= 30430/3619

In[2118]:= g[90, 500, val1 > 10, val2 > 100]

Out[2118]= 509/10

From the represented example the second method of work with named optional arguments is rather transparent. You can to familiarize with optional arguments in more detail in [22].

Other way of definition of optional arguments of functions and procedures consists in use of the template "_.", representing an optional argument with a default value specified by builtin Default function Default[w] = Value. Let's note, the necessary values for call Default[w] for a tool w must always precede an optional argument of the w tool. Values defined for Default[w] are saved in DefaultValues[w]. Fragment below illustrates told:

In[1346]:= Default[w] = 5;

In[1347]:= w[x_., y_., z_.] := {x, y, z}; {w[], w[42, 47], w[42]}

Out[1347]= {{5, 5, 5}, {42, 47, 5}, {42, 5, 5}}

More detailed information on this way can be found in [15] and by a call ?Default in the current session of Mathematica. At the same time all considered approaches to the organization of work with optional arguments do not give the chance to define values by default for an arbitrary tuple of formal arguments.

The reception described below on a simple example can be for this purpose used. Definition of a procedure G for which we going to make all three formal arguments x, y and z optional, is made out as follows: Res defines the list of formal arguments in string format, Def determines the list of values by default for all formal arguments, the procedure body is made out in the form "{Body}", moreover, of the G definition is complemented with an obligatory argument Opt which represents the binary list of signs whose elements correspond to Res list elements. The zero element of the Opt list determines non-obligation of the Res list element corresponding to it, and vice versa. After the specified definition of the procedure body (d) the StringReplaceVars [16] procedure which provides substitution in the procedure body of the actual arguments (sign 1) or their values by default (sign 0) is applied to it. So, the procedure call G[x, y, z, Opt] returns the simplified value of the source procedure body on the arguments transferred to it. The simple example visually illustrates told.

In[7]:= G[x_., y_., z_., Opt_] := Module[{Res = {"x", "y", "z"},

Def = Map[ToString1[#] &, {42, 47, 67}],

args = Map[ToString1[#] &, {x, y, z}], b, c, d},

d = "Simplify[{b = (x + y)/(x + z); c = b*x*y*z; (b + c)^2}]";

d = StringReplaceVars[d, Map[If[Opt[[#]] == 0, Res[[#]] >

Def[[#]], Res[[#]] > args[[#]]] &, Range[Length[Res]]]];

ToExpression[d][[1]]]

In[8]:= G[a, s, t, {0, 1, 1}]

Out[8]= ((42 + s)^2*(1 + 42*s*t)^2)/(42 + t)^2

In[9]:= G[a, s, t, {1, 1, 1}]

Out[9]= ((a + s)^2*(1 + a*s*t)^2)/(a + t)^2

In[10]:= G[a, s, t, {0, 0, 0}]

Out[10]= 138557641644601/11881

In certain cases the above reception can be rather useful.

The problem for testing of correctness of the tuple of formal arguments in the user modules, blocks or functions can be solved by procedure whose call CorrTupleArgs[x] returns True if tuple of formal arguments of a procedure or a function x is correct in the sense stated above, and False otherwise [8,16].

On the other hand, the problem of preliminary definition of correctness of the factual arguments passing to a procedure or a function is of a rather interesting. If tool has no mechanisms of testing of actual arguments passing to it at a call, then the call on incorrect actual arguments as a rule is returned unevaluated. The procedure TestActArgs is one of variants of solution of the problem, whose call TestActArgs[x, y] returns empty list if tuple of actual arguments meets the tuple of testing functions of the corresponding formal arguments of x, otherwise the procedure call trough y returns the integer list of numbers of the formal arguments to which inadmissible actual arguments are supposed to be passed [1-16].

Meantime, use of the above procedure assumes that testing for correctness of actual arguments for formal arguments with patterns {"__", "___"} is carried out only for the first elements of tuples of actual arguments passing to formal arguments with the appropriate patterns. Whereas further development of the procedure is left to the interested reader as an useful exercise. In addition, it should be noted the important circumstance. If in the traditional programming languages the identification of an arbitrary procedure or function is made according to its name, in case of Math–language the identification is made according to its heading. This circumstance is caused by that the definition of a procedure or function in the Math-language is made by the manner different from traditional [1]. Simultaneous existence of procedures of the same name with different headings in such situation is admissible as it illustrates a simple fragment:

In[2434]:= M[x_, y_] := Module[{}, x + y];

M[x_] := Module[{}, x^2]; M[y_] := Module[{}, y^3];

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

In[2435]:= Definition[M]

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 = 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]]

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

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]]

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___}

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].

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]], {"/;", "__", "___", "_", ":", "_:", "_.