среда, 20 января 2016 г.

#869. :, PROCEDURE, FUNCTION. Parameters at the left and at the right. Part 2

Original in Russian: http://programmingmindstream.blogspot.ru/2015/12/1167-procedure-function-2.html

The previous series was here: http://18delphi.blogspot.ru/2016/01/868-procedure-function-parameters-at.html.

The key words :, ;, FUNCTION, PROCEDURE and “parameters at the left” were considered there.

Now, let’s discuss the “parameters at the right”.

Suppose, we have an example with “parameters at the left”:

INTEGER FUNCTION Plus
 INTEGER IN A
 INTEGER IN B
 A B + >>> Result // adds A to B and write to Result
; // Plus
 
1 2 Plus . // calls the function and prints the result

This is a case of “typical” RPN.

How can we use infix notation?

This is where parameters at the right will help.

We rewrite the example using parameters at the right:

INTEGER FUNCTION Plus
 INTEGER IN A // parameter at the left
 ^ IN B // parameter at the RIGHT is passed by REFERENCE rather than by VALUE.
        //   It has to be dereferenced.
 A // value of parameter A
 B DO // dereferences the value B, i.e. calls the DO method on the word specified by B
 + >>> Result // adds A to B and write to Result
; // Plus
 
1 Plus 2 . // calls the function “INFIXELY” and prints the result

Note that parameters at the right are passed by reference.

We can also write:

1 Plus ( 2 Plus ( 3 Plus 4 ) ) .

The brackets is a must for now.

I’ll write how to do without them in a special article.

We can rewrite the example as follows:

INTEGER FUNCTION Plus
 INTEGER IN A // parameter at the left
 ^ IN B // parameter at the RIGHT is passed by REFERENCE rather than by VALUE.
        //   It has to be dereferenced.
 A // value of parameter A
 B |^ // dereferences the value B, i.e. calls the |^ method on the word specified by B
 + >>> Result // adds A to B and writhes to Result
; // Plus
 
1 Plus 2 . // calls the function “INFIXELY” and prints the result

|^ is used instead of DO here.

They are equal actually.

A bit later, I will write about the differences.

The |^ method is defined in axiomatic as follows:

: |^
  ^@ IN aRef
   
 %SUMMARY 'Dereferences the parameter at the left' ;
 aRef pop:Word:GetRef DO
; // |^

The details of  |^ implementation will also be described later.

Now, I will note that |^ uses DO, i.e. |^ is derived from DO.

Let’s go on.

Why are the parameters at the right passed by reference rather than by value?

There are many reasons, in particular "lazy evaluations".

Let’s look at the implementation of the Boolean operation AND and OR:

BOOLEAN operator AND
  BOOLEAN IN aFirst
  ^ IN aSecond
 %SUMMARY 'Double-sided rather than reverse polish &&' ;
 if aFirst then
  (
   if ( aSecond DO ) then
    ( true >>> Result )
   else
    ( false >>> Result )
   )
 else
  ( false >>> Result )
; // AND
 
BOOLEAN operator OR
  BOOLEAN IN aFirst
  ^ IN aSecond
 // Double-sided rather than reverse polish  ||
 if aFirst then
  ( Result := true )
 else
  if ( aSecond DO ) then
   ( Result := true )
  else
   ( Result := false )
; // OR

As we can see, the parameter aSecond is calculated ONLY in case we need to calculate the whole expression.

It means that the result of expression is not clear on the parameter aFirst.

The word operator is equal to the words : and FUNCTION. It merely stresses the words are “operator-related”.

In particular, operators can set "order of operations" as in Prolog, for example, to get rid of the brackets in the example with Plus (see above).

I’ll tell about it later.

Now, let us believe the operator is specified as follows:

WordAlias operator :
WordAlias OPERATOR :

What do we get using lazy evaluation?

Without lazy evaluation:

if ( ( anObject <> nil ) ( anObject .SomeMethod ) && ) then

we get Access Violation.

With lazy evaluation:

if ( ( anObject <> nil ) AND ( anObject .SomeMethod ) ) then

we get no Access Violation.

Hope you see why.

The operation <> is, by the way, defined in base axiomatic using parameters at the right and at the left and the operation =.

In this way:

BOOLEAN operator <>
  IN aLeft
  ^ IN aRight
 %SUMMARY 'Right-sided rather than reverse polish !=' ;
 Result := ( aLeft = ( aRight DO ) ! )
; //<>

No comments. Note that the operation ! is a postfix denial.

Let’s go on.

The fact that the reference to the word rather than value is passed means that, if a variable is given as the word, we can write to it.

Let us implement the examples of increment and decrement methods as in axiomatic:

VOID operator DEC
  ^ IN aWhatToDecrement
 aWhatToDecrement DO // dereferences the variable aWhatToDecrement
 1 - // decrement by 1
 >>>^ aWhatToDecrement // writes the value as pointed by the aWhatToDecrement
; // DEC
 
VOID operator INC
  ^ IN aWhatToIncrement
 aWhatToIncrement DO // dereferences the variable aWhatToDecrement
 1 + // increment by 1
 >>>^ aWhatToIncrement // writes the value as pointed by the aWhatToIncrement
; // INC
The call: 
INTEGER VAR A // specifies the integer variable A
0 >>> A // initializes it using zero
A . // prints
INC A // increases A by 1
A . // prints
DEC A // decreases A by 1
A . // prints

Sure, if we write Inc 1 we get compilation error, if not particularly run-time error.

Suppose also that we need to describe the methods IncBy and DecBy.

Here they are:

VOID operator DecBy
  ^ IN aWhatToDecrement
  ^ IN aDelta
 aWhatToDecrement DO // dereferences the variable aWhatToDecrement
 aDelta DO // dereferences the variable aDelta
 - // substraction
 >>>^ aWhatToDecrement //  writes the value as pointed by the aWhatToDecrement
; // DecBy
 
VOID operator IncBy
  ^ IN aWhatToIncrement
  ^ IN aDelta
 aWhatToIncrement DO // dereferences the variable aWhatToDecrement
 aDelta DO // dereferences the variable aDelta
 + // addition
 >>>^ aWhatToIncrement //  writes the value as pointed by the aWhatToIncrement
; // IncBy

The call:

INTEGER VAR A // specifies the integer variable A
0 >>> A // initializes it using zero
A . // - печатаем
IncBy A 2 // increases A by 2
A . // prints
DecBy A 2 // decreases A by 2
A . // prints

Let’s move on.

parameters at the right are also useful when dealing with lambda expressions.

Here is an example:

: Iteration
  ^ IN aLambda
 0 // initial value
 1 aLambda DO
 2 aLambda DO
 3 aLambda DO
 4 aLambda DO
 5 aLambda DO
 6 aLambda DO
 7 aLambda DO
 8 aLambda DO
 9 aLambda DO
 10 aLambda DO
; // Iteration
 
// The call:
 
Iteration ( IN A IN B A B + ) . // sums numbers from 0 to 10 and prints the result
 
// a shorter version:
 
Iteration + . // sums numbers from 0 to 10 and prints the result

The initial value can be factored out:

: Iteration
  ^ IN aLambda
 1 aLambda DO
 2 aLambda DO
 3 aLambda DO
 4 aLambda DO
 5 aLambda DO
 6 aLambda DO
 7 aLambda DO
 8 aLambda DO
 9 aLambda DO
 10 aLambda DO
; // Iteration
 
// The call:
 
0 Iteration ( IN A IN B A B + ) . // sums numbers from 0 to 10 and prints the result
 
// a shorter version:
 
0 Iteration + . // sums numbers from 0 to 10 and prints the result
 
1 Iteration * . // multiplies numbers from 1 to 10 and prints the result

Arrays and iteration (in Russian) can be used for them: 
  ^ IN aLambda
 [ 1 2 3 4 5 6 7 8 9 10 ] .for> ( aLambda DO )
; // Iteration
 
// The call:
 
0 Iteration ( IN A IN B A B + ) . // sums numbers from 0 to 10 and prints the result
 
// a shorter version:
 
0 Iteration + . // sums numbers from 0 to 10 and prints the result
 
1 Iteration * . // multiplies numbers from 1 to 10 and prints the result

Let us sum up.

Parameters at the right and dereferencing were analyzed.

We also considered writing values to the variables the parameters at the right point to and how parameters at the right can be used for lambda expressions.

We scraped the surface of arrays and iteration through arrays.

In the next article, the parameters at the right passed by reference will be discussed along with the way of implementing the operations like += -= and so on.

Hope the article was of some use for you.

понедельник, 18 января 2016 г.

#868. PROCEDURE, FUNCTION. Parameters at the left and at the right. Part 1

Original in Russian: http://programmingmindstream.blogspot.ru/2015/12/1163-wordworker-operator.html

With reference to - https://bitbucket.org/lulinalex/mindstream/wiki/Articles%20in%20English/Script%20engine%20organisation/A%20real%20example%20of%20code%20generation%20using%20the%20model.%20Mere%20code

The previous series was here - Caching. Let us talk about adding the nested elements.

They asked me about the word parameters (functions) - http://programmingmindstream.blogspot.ru/2015/12/1162.html?showComment=1450717154802#c256225446808977907 (in Russian)

I translate from Russian:

Where can I read about the WordWorker? What are the ways of passing arguments exist (at the right or atthe left, at the right without function executed)? I will appreciate if you give me a direct reference =)
Actually, it would be great you had thorough documentation, but I understand not all is at the same time.

Once I happen to be asked, I will try to describe how the words and word parameters are defined.

Commits history is available at - https://bitbucket.org/lulinalex/mindstream/commits/branch/B284_Inheritance_Try.

Let me stress:
Our script engine is based on the idea of the stack FORTH-machine - https://en.wikipedia.org/wiki/Forth_%28programming_language%29.

Thus, one should become familiar with FORTH (general guideline).

So.

The simplest word is defined as follows:

: // is the sign of word beginning
A // is the word name
 1 >>std::out // is the word code that prints the number 1 as well as
 1 . // prints the number 1
; // is the sign of word end
 
A // calls the word A

The example can be copied in the Example.script file and launched:

call.ms.script.exe Example.script or
call.ms.script.exe Example.script > a.out

The call.ms.script.exe utility is here - https://bitbucket.org/lulinalex/mindstream/src/0bea4adaed7cbc645faa484fcb38f8aae6562827/Examples/Scripts/call.ms.script.exe?at=B284_Inheritance_Try

Note:
The utility may not launch by default which means it is blocked by the anti-virus for it “came from an unreliable source”.

In this case, it should be checked with the anti-virus and added to the list of allowed applications.
Let’s go on.

It is obvious that, as in any programming language, our words may have parameters.

A simplest example:

: A
  IN aParam // specifies the aParam parameter, at the left of the word A
 aParam // returns the parameter value
 . // prints the parameter value 
: // A
 
1 A // calls the word A and passes the VALUE of the number 1 as a parameter value to it

The example can be developed with defining the parameter TYPE in this way:

: A
  INTEGER IN aParam // determines the INTEGER parameter aParam at the left of the word A
 aParam // returns the parameter value
 . // prints the parameter value
: // A
 
1 A // calls the word A and passes the VALUE of the number 1 as a parameter value to it

Thus, we can pass ONLY INTEGER values to our function.

The type of parameters and variables will be discussed further in a separate article.

Speaking aside, I’d like to recommend to see the description of the “axiomatic basis”- https://bitbucket.org/lulinalex/mindstream/src/a071353dbd21d3afaf8f42b774cc890e0f5a74ce/Examples/ScriptedAxiomatics/kwMain.rc.script?at=B284_Inheritance_Try&fileviewer=file-view-default  (commented in Russian)

So far, we have considered ONE parameter at the left.

Now, let us look at a NUMBER of parameters at the left.

The example:

: A
  INTEGER IN aParam1 // specifies the first parameter
  INTEGER IN aParam2 // specifies the second parameter
 aParam1 // returns the value of the parameter aParam1
 aParam2 // returns the value of the parameter aParam2
 + // gives the sum of the two values
 . // prints the result
; // A
 
1 2 A // calls the word A for two INTEGER values 1 and 2

Fine. We have discussed parameters passed to the word.

But, how can we get a value from the word?

Let us examine it.

A simplest example:

: A
  INTEGER IN aParam1 // specifies the first parameter
  INTEGER IN aParam2 // specifies the second parameter
 aParam1 // returns the value of the parameter aParam1
 aParam2 //  returns the value of the parameter aParam2
 + // gives the sum of the two values
 // prints nothing, simply leaves the result value in the stack
; // A
 
1 2 A // calls the word A for two INTEGER values 1 and 2
. // prints the value from the stack, in fact, the one returned by the function A

The technique of "leaving the value in the stack" is not only used in the “antediluvian FORTH" but in the quite “up-to-date Ruby" as well - https://en.wikipedia.org/wiki/Ruby_%28programming_language%29.

There is a negative aspect (in fact it is an advantage): the function called can FAIL to push anything in the stack, or push ONE SINGLE value, or a NUMBER of values.

The person that calls will not be able to control this process.

What’s to be done?

We need to define the TYPE of the value RETURNED.

An example:

INTEGER // specifies the type of the value returned and the “implicit value” Result
: A
  INTEGER IN aParam1 // specifies the first parameter
  INTEGER IN aParam2 // specifies the second parameter
 aParam1 // returns the value of the parameter aParam1
 aParam2 // returns the value of the parameter aParam2
 + // gives the sum of the two values
 >>> Result // pops the value from the stack and write it in the variable Result.
; // A
 
1 2 A // calls the word A for two INTEGER values 1 and 2
. // prints the value in the stack, in fact this is the value returned by the function A

In this case, the script engine ENSURES that ONE and ONLY ONE integer value will be returned.

There is a “but”.

The script engine controls the values returned but not popped from the stack.

We can write as follows.

INTEGER // specifies the type of the value returned and the “implicit value” Result
: A
  INTEGER IN aParam1 // specifies the first parameter
  INTEGER IN aParam2 // specifies the second parameter
 aParam1 // returns the value of the parameter aParam1
 aParam2 // returns the value of the parameter aParam2 
 + // gives the sum of the two values aParam1 and aParam2
 + // gives the sum of the previous value and the value in the stack
 >>> Result // pops the value from the stack and pushes it in the write it in the variable Result.
; // A
 
1 2 3 A // calls the word A for THREE integer values 1, 2 and 3

Sometimes it helps but what about when you want the “total control”?

For this, we have “analogues” of the word :, namely FUNCTION and PROCEDURE.

The example:

INTEGER // specifies the type of the value returned and the “implicit value” Result
FUNCTION // FUNCTION is used instead :
 A
  INTEGER IN aParam1 // specifies the first parameter
  INTEGER IN aParam2 // specifies the second parameter
 aParam1 // returns the value of the parameter aParam1
 aParam2 // returns the value of the parameter aParam2
 + // gives the sum of the two values
 >>> Result // pops the value from the stack and write it in the variable Result.
; // A
 
1 2 A // calls the word A for two INTEGER values 1 and 2
. // prints the value in the stack, in fact this is the value returned by the function A

In this case, both the number of inputs and outputs will be controlled by the script engine.

Here is an example of using the word PROCEDURE:

PROCEDURE // PROCEDURE is used instead of :
 A
  INTEGER IN aParam1 // specifies the first parameter
  INTEGER IN aParam2 // specifies the second parameter
 aParam1 // returns the value of the parameter aParam1
 aParam2 // returns the value of the parameter aParam2
 + // gives the sum of the two values
 . // prints the result value
; // A
 
1 2 A // calls the word A for two INTEGER values 1 and 2

The word PROCEDURE ENSURES that NO VALUES will be returned by the word.

Let’s sum up.

In the article the key words ( :, ;, IN, FUNCTION, PROCEDURE), passing the parameters to the words and returning values to them were considered.

We have scratched the surface of value typing.

Apart from INTEGER type there are STRING, OBJECT, CLASS, INTERFACE, CHAR, ARRAY, FILE, BOOLEAN.

There is also ANY that stands for “any type value”, and PRINTABLE that stands for “any printable value”, and VOID that stands for “sure value absense".

Other types including ITERATABLE, ORDINAL, and ATOMIC will be discussed later.

For now, please find the example of axiomatic:

INTEGER BOOLEAN TYPE ORDINAL
STRING ORDINAL TYPE ATOMIC
ATOMIC TYPE COMPARABLE
 
FILE ARRAY TYPE ITERATABLE
ITERATABLE ATOMIC CASTABLE INTERFACE TYPE ANY
ANY TYPE VARIANT
 
ARRAY TYPE ITERATOR
 
FUNCTOR TYPE VAR_REF

Next, we will discuss the “parameters at the right” (why we need them and how to use them).

Hope, the article was of some use for you.