From 6f6ae78d193a621e437c33358f26eaaf85175105 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Del=20Pino?= <stephane.delpino44@gmail.com> Date: Wed, 1 Jun 2022 18:08:26 +0200 Subject: [PATCH] Fix a set of typos and reword a few things --- doc/userdoc.org | 248 ++++++++++++++++++++++++------------------------ 1 file changed, 124 insertions(+), 124 deletions(-) diff --git a/doc/userdoc.org b/doc/userdoc.org index d81ee102d..d9d740710 100644 --- a/doc/userdoc.org +++ b/doc/userdoc.org @@ -56,7 +56,7 @@ capabilities of the code. ** An example For instance, the following code builds a uniform Cartesian grid of $]-1,1[^2$ made of $20\times20$ cells and transforms it by displacing the -mesh nodes according to a user defined vector field $T: \mathbb{R}^2 +mesh nodes according to a user-defined vector field $T: \mathbb{R}^2 \to \mathbb{R}^2$. #+NAME: introduction-example #+BEGIN_SRC pugs :exports both :results output @@ -81,7 +81,7 @@ The example is quite easy to read. classical mathematical functions ($\sin$, $\cos$, ...). The ~writer~ module is used to save meshes or discrete functions to files using various formats. -- The second block of data defines variables of different kind +- The second block of data defines variables of different types - ~pi~ is a real value that is initialized by an approximation of $\pi$. - ~theta~ is the real value function $\theta$ defined by \begin{equation*} @@ -149,7 +149,7 @@ already be discussed. ** Concepts and design -As it was already stated ~pugs~ can be viewed as a collection of +As it was already stated, ~pugs~ can be viewed as a collection of numerical methods or utilities that can be assembled together, using a user friendly language, to build simulation scenarios. @@ -165,14 +165,14 @@ kind. Generally, in order to run a calculation, one has to define a set of data and parameters. This can simply be definition of a discretization parameter such as the mesh size. One can also specify boundary conditions, equations of state, source terms for a specific -model. Choosing a numerical method or even more setting the model -itself is common in large code. +model. Choosing a numerical method or even more, setting the model +itself, is common in large codes. In ~pugs~, all these "parameters" are set through a -DSL[fn:DSL-def]. Thus, when ~pugs~ is launched, it actually executes the +DSL[fn:DSL-def]. Thus, when ~pugs~ is launched, it actually executes a provided script. A ~C++~ function is associated to each instruction of -the script. The ~C++~ components of ~pugs~ are completely unaware of the -other ones. ~pugs~ interpreter is responsible of data flow between the +the script. The ~C++~ components of ~pugs~ are completely unaware one of +the others. ~pugs~ interpreter is responsible of data flow between the components: it manages the data transfer between those ~C++~ components and ensures that the workflow is properly defined. @@ -189,25 +189,25 @@ methods or their settings. - Data files are not flexible. This implies in one hand that application scenarios must be known somehow precisely to reflect - possible options combinations and on the other hand even defining a + possible option combinations and on the other hand even defining a specific initial data may require the creation of a new option and the associated code (in ~C++~ for instance). \\ - It is quite common to fix the last point by adding a local - interpreter to evaluate user functions for instance. + Usually, the last point is addressed by adding a local interpreter + to evaluate user functions. - Data files may contain irrelevant information. Actually, it is quite common to allow to define options that are valid but irrelevant to a given scenario. This policy can be changed but it is generally not an easy task and requires more work from the user (which can be a good thing). -- It is quite common that data files become obsolete. An option was - not the right one, or its type changed to allow other - contexts... This puts pressure on the user. +- Generally data files become rapidly obsolete. An option was not the + right one, or its type changed to allow other contexts... This puts + pressure on the user. - Even worst, options meaning can depend on other - options. Unfortunately, it happens quite easily. For instance, a + options. Unfortunately, this happens commonly. For instance, a global option can change implicitly the treatment associated to - another one. This is quite dangerous since writing or reading the - data file requires an important and up to date knowledge of the - code's internals. + another one. This is dangerous since writing or reading the data + file requires an important and up to date knowledge of the code's + internals. - Another major difficulty when dealing with data files is to check the compatibility of provided options. @@ -246,16 +246,15 @@ solution to all problems. However, it offers some advantages. - It allows to structure the code in the sense that new developments have to be designed not only focusing on the result but also on the way it should be used (its interactions with the scripting language). -- In the same idea, it provides a framework that should ease the - desired principle of "do simple things and do them well". +- In the same idea, it provides a framework that drives the desired + principle of "do simple things and do them well". - There are no hidden dependencies between numerical options: the DSL - code is easier to read (than data files) and it is more difficult to - get it obsolete (this is not that true in early developments since + code is easier to read (than data files) and is less likely to + become obsolete (this is not that true in early developments since the language itself and some concepts are still likely to change). -- The simulation scenario is *defined* by the script, it is to the - responsibility of the user and not to the charge of the code to - check its meaning. - +- The simulation scenario is *defined* by the script, it is the + responsibility of the user to check its meaning (not to the charge + of the code). ***** ~pugs~ language purpose @@ -263,7 +262,7 @@ solution to all problems. However, it offers some advantages. tested. These tools should ideally be small pieces of ~C++~ code that do one single thing and do it well. -Another purpose of the language is to allow perform high-level +Another purpose of the language is to allow to perform high-level calculations. In other words, the language defines a data flow and checks that each ~C++~ piece of code is used correctly. Since each piece of code acts as a pure function (arguments are unchanged by calls), @@ -293,7 +292,7 @@ writing of new methods. create *new functions in the language*. Moreover, if a new method is close to an existing one, it is generally *better* to use completely new underlying ~C++~ code than to patch existing methods. Starting - from a *copy* of the existing code is *encouraged* for + from a *copy* of the existing code ~C++~ is *encouraged* for developments. This may sound weird since classical development guidelines encourage inheritance or early redesign. Actually, this policy is the result of the following discussion. @@ -323,13 +322,14 @@ writing of new methods. - This implies an /a priori/ safer code: utilities are well tested and validated. - It saves development time obviously. - - Numerical methods code is not polluted by environment instructions - (data initialization, error calculation, post-processing,...) + - The code of numerical methods is not polluted by environment + instructions (data initialization, error calculation, + post-processing,...) - The counterpart is somehow classical. In the one hand, the knowledge of existing utilities is required, this document tries to address a part of it. In the other hand, if the developer requires a new utility, a good practice is to discuss with the - others to check if it could benefit to them. Then one can + other ones to check if it could benefit to them. Then one can determine if it should integrate rapidly or not the main development branch. @@ -338,8 +338,8 @@ writing of new methods. As it was already pointed out above, general purpose languages offer to much freedom: it is not easy to protect data. For instance in the ~pugs~ DSL, non basic variables are constant (see paragraph -[[high-level-types]]). It is important since it prevents the user to -modify data in inconsistent ways. Also, one must keep in mind that +[[high-level-types]]). It is important since it prevents the user from +modifying data in inconsistent ways. Also, one must keep in mind that constraining the expressiveness is actually a strength. As said before, one can warranty coherence of the data, perform calculations without paying attention to the parallelism aspects,... Observe that @@ -347,18 +347,17 @@ it is not a limitation: if the DSL's field of application needs to be extended, it is always possible. But these extensions should never break the rule that a DSL must not become a general purpose language. -Providing a language close to the application (or here in particular -close to the Mathematics language) reduces the gap between the -application and its expression (code): Domain Specific Languages are -made for that. +Providing a language close to the application reduces the gap between +the application and its expression (code): Domain Specific Languages +are made for that. Finally, python is ugly. *** A high-level language Following the previous discussion, the reader should now understand -the motivations that drive the design choices which made of ~pugs~ some -kind of a ~C++~ toolbox driven by a user friendly language. +the motivations that drove the design choices that conduct to build +~pugs~ as a ~C++~ toolbox driven by a user friendly language. #+begin_verse Keep it simple and relevant! @@ -366,15 +365,15 @@ Keep it simple and relevant! In the development process of an application, the easy step is generally the implementation itself. It is even more true when the -developer feels that the changes to code are natural and that the +developer feels that changes to the code are natural and that the modifications themselves look easy. Obviously, any experienced programmer knows that writing the code is only the first step of a much longer process which requires rigorous tests and validations, the enrichment of a non-regression database. Generally one also desires to ensure that the development is used within the correct bounds which -requires to implement checking and data verification. In a perfect -world, an up-to-date documentation of the functionality and its domain -of validity. +requires to implement data verification. In a perfect world, an +up-to-date documentation of the functionality and its domain of +validity. This is even more true when defining a language (or a DSL). Enriching a language syntax (or grammar) is not something that must be done to @@ -411,9 +410,8 @@ write errors. ** Variables In order to simplify the presentation, before going further, we -introduce the construction that allows to print data to the -terminal. It follows ~C++~ streams construction for convenience. For -instance +introduce the syntax that allows to print data to the terminal. It +follows ~C++~ streams construction for convenience. For instance #+NAME: cout-preamble-example #+BEGIN_SRC pugs :exports both :results output cout << "2+3 = " << 2+3 << "\n"; @@ -483,7 +481,7 @@ There is not to much to comment, reading is quite natural and - ~;~ marks the end of the instruction. -One for instance can write +For instance, one can write #+NAME: simple-affectations-example #+BEGIN_SRC pugs :exports both :results output import math; // to load sin function @@ -497,8 +495,8 @@ One for instance can write cout << "a = " << a << " b = " << b << " x = " << x << "\n"; #+END_SRC -In this example, we imported the `math` module which provides the -`sin` function. and we used the ~N~ data type of natural integers +In this example, we import the ~math~ module which provides the ~sin~ +function and we use the ~N~ data type of natural integers ($\mathbb{N}\equiv\mathbb{Z}_{\ge0}$). Running the example gives the following result. @@ -518,11 +516,11 @@ detects uninitialized values. For instance, produces the following compilation error #+results: uninitialized-variable -For more complex constructions, it can be very difficult to detect at -compile time, this is why it is *encourage* to use variable definition -(see [[definition-simple-variables]]). +For more complex constructions, it can be very difficult to detect it +at /compile time/, this is why it is *encourage* to use variable +definition (see [[definition-simple-variables]]). -Observe nonetheless, ~pugs~ checks at runtime that used variables are +Observe nonetheless, ~pugs~ checks at /run time/ that used variables are correctly defined. If not an error is produced. #+END_warning @@ -538,10 +536,9 @@ variable ~v~ of a given type ~V~, from an expression one writes - ~:~ is a separation token (can be read as "/in/" in this context), - ~V~ is the identifier of the type, - ~,~ is the separator that indicates the beginning of the affectation, -- ~expression~ is some code that provide a value (it can be another - variable, an expression, the result of a function,...), - and -- ~;~ marks the end of the instruction. +- ~expression~ is some code that provides a value (it can be another + variable, an expression, the result of a function,...), and +- ~;~ marks the end of the instruction (here the definition of ~v~). A practical example is #+NAME: simple-definition-example @@ -562,8 +559,8 @@ which produces the result In pugs scripts, variables have a precise lifetime. They are defined within scopes. The main scope is implicitly defined and sub-scopes are enclosed between bracket pairs: ~{~ and ~}~. Following ~C++~, a variable -exits (can be used) as soon as it has been declare until the end of -the scope where it has been declared. At this point we give a few +exits (can be used) as soon as it has been declared and until the end +of the scope (where it has been declared). At this point we give a few examples. **** A variable cannot be used before its declaration @@ -608,7 +605,7 @@ examples. #+END_SRC #+results: nested-scope-variable-example This example is self explanatory. Obviously such constructions are -generally a wrong idea. This kind of constructions may appear in loops +generally *bad ideas*. This kind of constructions can appear in loops where the variables defined in blocks follow the same lifetime rules. *** Basic types<<basic-types>> @@ -634,7 +631,7 @@ This may sound strange but there are few reasons for that. language we adopt the same rule to avoid ambiguity. - A second reason is connected to the first one. Since ~pugs~ aims at providing numerical methods for problems in dimension $1$, $2$ or - $3$, this allow to distinguish the nature of the underlying objects. + $3$, this allows to distinguish the nature of the underlying objects. - It is natural to consider that the coordinates of the vertices defining a mesh in dimension $d$ are elements of $\mathbb{R}^d$, - or that a velocity or a displacement are also defined as @@ -645,8 +642,9 @@ This may sound strange but there are few reasons for that. **** Expression types -The interpreter gives type to some special expressions. -- special boolean (type ~B~) expressions. Two *keywords* allow to define +The language associates statically some types to several special +expressions. +- Special boolean (type ~B~) expressions. Two *keywords* allow to define boolean values: ~true~ and ~false~. - Integers (type ~Z~) are defined as a contiguous list of digits. - For instance, the code ~0123~ is interpreted as the integer $123$. @@ -685,9 +683,8 @@ The interpreter gives type to some special expressions. **** Variables of basic types are stored by value This means that each variable of basic type allocates its own memory -to store its data. This is the natural behavior for variables thus one -understands easily that in the following example: - +to store its data. This is the natural behavior for variables. It is +illustrated in the following example #+NAME: basic-type-value-storage #+BEGIN_SRC pugs :exports both :results output let a:N, a = 3; @@ -728,17 +725,17 @@ conversion in general. #+BEGIN_note Actually, there are only three situations for which implicit type -conversion can occur -- when the value is given as a parameter of a function, or -- when the value is used as the returned value of a function. -- when the value is used to define a tuple -This will be detailed in section [[functions]] and [[tuples]] +conversion can occur: when the value is +- given as a parameter of a function, +- used as the returned value of a function, or +- used to define a tuple +This will be illustrated in section [[functions]] and [[tuples]] #+END_note -This means that all affectation, unary and binary operators are -defined explicitly for supported types. +This means that all affectations, unary operators and binary operators +are defined explicitly for supported types. -Here is a table of implicit type conversion *when allowed*. +Here is a table of implicit type conversions *when allowed*. | expected type | convertible types | |---------------+------------------------------------------------| @@ -807,8 +804,10 @@ affectations are /instructions/. As already mentioned, operator ~=~ is defined for *all* types in ~pugs~ if the right hand side expression has the *same* type as the left hand side variable. This is true for basic types as well as for high-level -types. We now give the complete list of supported ~=~ affectations. The -lists are sorted by type of left hand side variable. +types. + +We now give the complete list of supported ~=~ affectations. The lists +are sorted by type of left hand side variable. - ~B~: boolean left hand side variable. One is only allowed to affect boolean values. @@ -935,8 +934,8 @@ lists are sorted by type of left hand side variable. the output is #+RESULTS: affectation-to-R3x3-from-list -- ~string~ left hand side variable. Expressions of any basic types can - be used as the right hand side. +- ~string~ left hand side variable. Expressions of any basic type can be + used as the right hand side. | ~=~ allowed expression type | |---------------------------| | ~B~ | @@ -1008,8 +1007,8 @@ lists are sorted by type of left hand side variable. |----------------------------| | ~R^3x3~ | -- ~string~ left hand side variable. Expressions of any basic types can - be used as the right hand side. +- ~string~ left hand side variable. Expressions of any basic type can be + used as the right hand side. | ~+=~ allowed expression type | |----------------------------| | ~B~ | @@ -1263,10 +1262,10 @@ counterparts for commodity. The ~+~ unary operator is a convenient operator that is *elided* when parsing the script. -For basic types, when these operators are defined, they return a value -of the same type as the argument (except if the argument is a ~N~, then -the result is a ~Z~). These operators can be defined for high-level -types. +For basic types, when the operators ~not~, ~+~, ~-~, ~++~ or ~--~ are defined, +they return a value of the same type as the argument (except for the +operator ~-~ if the argument is a ~N~, then the result is a ~Z~). These +operators can be defined for high-level types. - The ~not~ operator is only defined for boolean values (~B~). - The ~-~ unary operator is defined for numeric basic types: ~B~, ~N~, ~Z~, ~R~, ~R^1~, ~R^2~, ~R^3~, ~R^1x1~, ~R^2x2~ and ~R^3x3~. It is not defined @@ -1312,7 +1311,7 @@ This code produces Syntax for binary operators follows again a classical structure if ~exp1~ and ~exp2~ denotes two expressions and if ~op~ denotes a binary -operator, one writes simply ~exp1 op exp2~. +operator, one simply writes ~exp1 op exp2~. Here is the list of binary operators | keyword | operator | @@ -1589,14 +1588,14 @@ the output is *** High-level types<<high-level-types>> -Aside from the basic type described in the previous section, ~pugs~ also -deals with "high-level" types. This term is more to understand as +Aside from the basic types described in the previous section, ~pugs~ +also deals with "high-level" types. This term is more to understand as "non-basic types". The ~pugs~ language is not object oriented to keep it simple. -To fix ideas let use give a few high-level type of data. These can be -for instance meshes (the ~mesh~ type), output streams (the ~ostream~ -type), boundary descriptors (~boundary~), quadrature formula +To fix ideas, let us give examples of a few high-level data +types. These can be meshes (the ~mesh~ type), output streams (the +~ostream~ type), boundary descriptors (~boundary~), quadrature formula (~quadrature~), discrete functions (~Vh~),... One can already see that the complexity of these types may vary a lot. @@ -1606,7 +1605,7 @@ high-level types are not available in directly the language but they are loaded on demand (using the ~import~ keyword in the preamble of the script). -The second difference is that data of these type are *constant*. More +The second difference is that data of these types are *constant*. More precisely, the content of high-level variables can be replaced by a new one *but* it cannot be modified. For this reason, the following operators can never be applied to variables of this kind @@ -1620,11 +1619,11 @@ operators can never be applied to variables of this kind | ~/=~ | assignment by quotient | We conclude by stating that if access operator ~[]~ can eventually be -overloaded for high-level types, it is quite difficult and should be -done with care. It is not recommended. +overloaded for high-level types, it should be done with care. It is +not recommended. Finally, the last difference lies in the fact that high-level types -use shallow copy and not value copy as it is the case for basic +use shallow copies and not value copies as it is the case for basic types. This is transparent to the user and provides the intuitive (similar) behavior since data of high-level variables are constant. To illustrate this, let us consider the following example. @@ -1640,28 +1639,28 @@ illustrate this, let us consider the following example. #+END_SRC In this example, we are dealing with 3 ~mesh~ variables. -- First ~m1~ is defined as a uniform cartesian mesh in dimension 2 of +- First, ~m1~ is defined as a uniform cartesian mesh in dimension 2 of $]0,1[^2$ made of $10\times10$ identical square cells. - Then ~m2~ is a copy of the variable ~m1~. It is a copy of the variable, but the underlying mesh is *the same*! There is no duplication of the mesh in memory. -- Then the mesh variable ~m3~ is *defined* to refer to a *new* mesh. It is +- Then, the mesh variable ~m3~ is *defined* to refer to a *new* mesh. It is /similar/ to the mesh contained in ~m1~ and ~m2~, but it is *not* the same one! When ~m3~ is defined two meshes, (and two connectivities) are resident in memory. One of the mesh is referred by either ~m1~ or ~m2~ and the other one is referred by ~m3~. - Finally, the last instruction (~m3 = m1;~) sets ~m3~ to also refer the mesh referred by ~m1~ and ~m2~. Since no other variable refers to its - former mesh, it is destroyed (memory is freed). At the end of the - program, all the variables ~m1~, ~m2~ and ~m3~ are referring to the same - mesh, and there is only one mesh that resides in memory. + former mesh, the mesh is destroyed (memory is freed). At the end of + the program, all the variables ~m1~, ~m2~ and ~m3~ are referring to the + same mesh, and there is only one mesh that resides in memory. *** Compound types The ~pugs~ language allow to deal with compound types. The idea is to -define lists variables as a member of a product space (each variable -belongs to one of them, each variable has a simple type: basic or -high-level). +define a list of variables as a member of a product space (each +variable belongs to one of them, each variable has a simple type: +basic or high-level). **** Compound declaration @@ -1712,8 +1711,9 @@ It produces the following error #+results: invalid-compound-definition which is easy to fix. -Another potential mistake is that all variables are marked to be -defined at the same time. Thus one cannot use construction like this: +Another potential mistake is that all variables of the list are marked +as defined at the same time. Thus one cannot use construction like +this: #+NAME: undeclared-compound-definition #+BEGIN_SRC pugs-error :exports both :results output let (x,y):R*R, (x,y) = (0,2+x); @@ -1762,7 +1762,8 @@ that case. The last special type construction is the ability to deal with tuples in the ~pugs~ language. The tuples we are describing here are lists of data of a *unique* and *simple* type (one cannot use compound types to -define tuples). +define tuples). Tuples in the ~pugs~ language have *no relationship* with +~C++~'s ~std::tuple~ these are two completely different notions. The list of values given to the tuple must be *implicitly* convertible to the type of tuple elements (see the conversion table in section @@ -1809,11 +1810,11 @@ boundary conditions to a method. ** Statements The ~pugs~ language supports classical statements to control the data -flow. For simplicity, these statements syntax follows their ~C++~ +flow. For simplicity, these statements syntax follow their ~C++~ counterpart. The only statement that is not implemented in ~pugs~ is the -~switch...case~. This may change but in one hand, up to it was never -necessary (we did not use chained ~if...else~ statements), and on the -other hand, keeping the language as simple as possible remains the +~switch...case~. This may change but in the one hand, up now to it was +never necessary (we did not use chained ~if...else~ statements), and on +the other hand, keeping the language as simple as possible remains the policy in ~pugs~ development. *** ~if...else~ statement @@ -1838,9 +1839,10 @@ The condition itself *must be* a boolean value (of type ~B~). generates the following expected output. The second output is hopefully not executed. #+results: if-instruction - It is probably better to use the ~else~ keyword to obtain the same -result +result. + +An example of the use of the ~else~ keyword follows. #+NAME: if-else-instruction #+BEGIN_SRC pugs :exports both :results output if (2<=1) @@ -1955,7 +1957,7 @@ One gets *** ~do...while~ loops -The second kind of loops that can be written is the ~do...while~ +The second kind of loops that can be supported is the ~do...while~ construction which executes /at least/ one time the enclosed ~statement~. #+BEGIN_SRC pugs :exports code do statement while (condition); @@ -2002,9 +2004,8 @@ The ~statement~ is either a single instruction or a block of instructions. The ~condition~ is an expression of boolean value (type ~B~). -This time is the ~condition~ is never satisfied (never ~true~), the -~statment~ is not executed. - +This time is the ~condition~ is not satisfied (~false~ when reaching the +~while~ instruction), the ~statment~ is never executed. An example of the ~while~ loop is the following. #+NAME: while-block @@ -2046,7 +2047,7 @@ An example of use of the ~continue~ keyword is The result is #+results: nested-continue -Replacing the ~continue~ keyword by a ~break~ +Replacing the ~continue~ keyword by a ~break~ (and changing the test) #+NAME: nested-break #+BEGIN_SRC pugs :exports both :results output for (let i:N, i = 0; i < 5; ++i) { @@ -2067,15 +2068,14 @@ Obviously the behavior is the same using ~do...while~ or ~while~ loops. The ~pugs~ language allow the manipulation and definition of functions. These are *mathematical functions* and are not functions as -functions in ~C++~. The functions in the ~pugs~ language are *not -subroutines*. +functions in ~C++~: functions in the ~pugs~ language are *not subroutines*. To be more precise, a function $f$ follows the following structure \begin{align*} \mbox{let }f:& X_1\times \cdots \times X_n \to Y_1\times \cdots \times Y_m,\\ & (x_1,\ldots,x_n)\mapsto (y_1,\ldots,y_m)=f(x_1,\ldots,x_n), \end{align*} -where $n,m\in\mathbb{N}$, and where ${(X_i)}_{0\le i\le n}$ and ${(Y_i)}_{0\le +where $n,m\in\mathbb{N}_{\ge1}$, and where ${(X_i)}_{0\le i\le n}$ and ${(Y_i)}_{0\le i\le m}$ are /simple/ types. Actually $X_1\times \cdots \times X_n$ and $Y_1\times \cdots \times Y_m$ are /compound/ types. @@ -2092,7 +2092,7 @@ or if ~(y1,...,ym)~ has already been defined in ~Y1*...*Ym~ (y1,...,ym) = f(x1,...,xn); #+END_SRC -The ~pugs~ language handles two kinds of functions. User defined +The ~pugs~ language handles two kinds of functions. User-defined functions (see [[user-defined-functions]]) and builtin functions (see [[builtin-functions]]). They behave essentially the same and are both constant. In this context, it means that one cannot just declare or @@ -2110,7 +2110,7 @@ computer science sense. The reason for that is that they can eventually have side effects. A good example for that, is that it is possible to modify the random seed used by the code. In that case, the modified value is not a variable of the language itself but the -internal random seed itself. +internal random seed. #+END_note *** Implicit type conversion for parameters and returned values @@ -2161,7 +2161,6 @@ returned type cout << "f(3.2) = " << f(2.3) << "\n"; #+END_SRC -One observes the implicit conversion of the values passed by argument. #+results: R-to-R1-function Using compound types as input and output, one can write @@ -2232,7 +2231,8 @@ the value of ~a~ is changed, the value function is implicitly modified. /This is a dangerous feature and should be avoid!/ #+results: non-arg-variables-in-functions -Since functions themselves are variables one can call functions in +Since functions themselves are variables one can use functions in +function expressions. #+NAME: functions-in-functions #+BEGIN_SRC pugs :exports both :results output let plus: R -> R, x -> (x>0)*x; @@ -2290,7 +2290,7 @@ in ~pugs~ of the following ~C++~ code int f(int i) { return g(i); } #+END_SRC -Moreover simple recursion if forbidden for similar reasons, since +Moreover simple recursion is forbidden for similar reasons, since functions are made of a single expression (one cannot use statements), there would be no way to end the recursion. Thus, the code #+NAME: no-recursion -- GitLab