OM LOOP


 

omloop is a special form of generic function performing iterative and accumulative procedures. By double clicking on its icon, a window patch is displayed where other functions are present: The iterators, the accumulators and the outputs. These functions are to be used exclusively in omloop's patch and they may not be evaluated directly inside the patch. However other standard lisp and om functions may be used and evaluated inside omloop's patch.

Initially omloop comes without inputs. Inputs can be added (option+right arrow) in the same manner as standard patches. These inputs take as arguments mainly lists of any data type.

omloop's output depends on the choice of iterators, accumulators and output functions, and the way they are combined together. This makes possible a wide range and an unlimited palette of iterative procedures. omloop may have unlimited outputs depending on the additional inputs of loopdo (eachTime) and finaldo (finally).

 

Iterators

These clauses perform variable stepping between each execution of the loop body, or termination tests.

 

forloop

(forloop from to &optional by )

[generic-function]

Inputs

from integer

to integer

Optional input

by number

forloop sets the number of iteration steps. At each step forloop returns an integer between <from> and <to>.

Opening the third input <by> will control the step size. <by> may be a floating-point number.

Default values:

<from> 0

<to> 10

<by> 1

Examples:

 

In this example omloop behaves as an arithm-ser module, returning an arithmetical series from 1 to 10 with a step of 1. This is possible by using forloop iterator.

The output of forloop is collected using listing (collect) then returned by finaldo (finally). (Please refer to these modules for further information).

Another example using forloop illustrating the control of another iterator (listloop):

listloop will enumerates a list of 12 elements. forloop controls the accumulation of these in the collector listing (collect). Having 5 as an argument in the second input <to>, forloop will stop the process allowing listing (collect) to return only the first five elements of the list.

The evaluation of this loop will return:

? OM->(1 2 3 4 5)

 

whileloop

(whileloop expr )

[generic-function]

Input

expr any data type

whileloop controls iteration by testing the input value <expr>. While this value is true (t) the iteration will go on. When whileloop gets a nil value, then iteration is terminated.

Examples:

In this simple example, listloop enumerates the list (1 2 3 4 nil 5 6 7 8) sending each element to the collector (listing (collect)) and to whileloop simultanaeously. whileloop will test its input. When the value nil is returned, the iteration is interrupted. The collector will return:

? OM->(1 2 3 4)

listloop

(listloop list &optional by )

[generic-function]

Input

list list

Optional input

by symbol or Lambda-function

listloop iterates a list, returning each element of <list> one by one.

Examples:

 

In this example listloop enumerates the list (1 2 3 4 5) sending each element to the lisp function list. list will construct a list with each element. Then every list will be collected by the collector listing (collect), and returned as a list of lists:

? OM->((1) (2) (3) (4) (5))

Remember, one cannot evaluate omloop from within its patch. The list (1 2 3 4 5) could also have been connected from outside the patch directly through an additional input of omloop:

The optional input <by> permits the control of stepping on <list>. Using cdr or the lisp function nthcdr one can skip elements of <list>:

 

In the patch above, nthcdr was used to skip one element out of two in <list>.The patch returns:

? OM->(1 3 5 7 9)

To skip two elements out of three, 3 must be entered in the first input of nthcdr which will return:

? OM->(1 4 7)

 

onlistloop

(onlistloop list &optional by )

[generic-function]

Input

list list

Optional input

by number

onlistloop performs the cdr operation on <list> recursively, returning all the list, then all the list but the first element, all the list but the first two elements, and so on.

Example:

 

This patch shows the simple enumeration of onlistloop of the list (1 2 3 4 5). It returns:

? OM->((1 2 3 4 5) (2 3 4 5) (3 4 5) (4 5) (5))

 

Collectors

 

The Collectors perform value accumulation.

Note:

Some collectors are special cases of the collector accumulator (accum). Therefore for each of these we will present the equivalent omloop-patch with accumulator. For this reason it is advised to read accumulator (accum) first.

 

counter (count)

(counter what? &optional retard )

[generic-function]

Input

what? any type of data

Ouputs (from left to right)

- The first output triggers a collection and adds an element to the resulting list

- The second output returns the current state of the collection without triggering the evaluation, and without adding any element to that collection

- The third output reinitialize the collector, returning the initial value 0

counter counts the number of times that <what?> expression has a non- nilvalue.

Examples:

Given the following list of six elements (a b nil c nil d), the output of the accumulator counter will be:

? OM->4

The same patch using accumulator and a binary Om function patch in lambda mode:

accumulator will output the number of non-nil elements of the list following the conditional user function we have made "patchcountif" and connected into its third input <fun>.

"patchcountif" being a binary function (taking two arguments), will test every element of <list> coming from the iterator listloop into its second input1.

If the element is non-nil omif will increment the internal state value of accumulator by using the lisp function incf. If the element is nil, omif will return nil, and therefore the stored result in accumulator will not be incremented.

 

sum

(sumwhat? &optional retard )

[generic-function]

Input

what? number

Ouputs (from left to right)

- The first output triggers a collection and adds an element to the resulting list

- The second output returns the current state of the collection without triggering the evaluation, and without adding any element to that collection

- The third output reinitialize the collector, returning the initial value 0

This collector returns the sum of its collected elements.

Examples:

This patch returns

? OM->10

being the sum of (1 + 2 +3 +4)

The same result using accumulator:

In this case, one could also use apply:

(apply '+ '(1 2 3 4))

 

minim (min)

(minimwhat? &optional retard )

[generic-function]

Input

what? number

Ouputs (from left to right)

- The first output triggers a collection and adds an element to the resulting list

- The second output returns the current state of the collection without triggering the evaluation, and without adding any element to that collection

- The third output reinitialize the collector, returning the initial value 4294967296

Outputs the minimum value of its collected elements

Examples:

This patch returns:

? OM->3

The same output using list-min:

 

 

maxi (max)

(maxi what? &optional retard )

[generic-function]

Input

what? number

Ouputs (from left to right)

- The first output triggers a collection and adds an element to the resulting list

- The second output returns the current state of the collection without triggering the evaluation, and without adding any element to that collection

- The third output reinitialize the collector, returning the initial value -4294967296

Outputs the maximum value of its collected elements

Example:

This patch returns:

? OM->85

The same output using list-max:

 

listing (collect)

(listing what? &optional retard )

[generic-function]

Input

what? any type of data

Ouputs (from left to right)

- The first output triggers a collection and adds an element to the resulting list

- The second output returns the current state of the collection without triggering the evaluation, and without adding any element to that collection

- The third output reinitialize the collector, returning the initial value nil

During each iteration listing collects the value of <what?> into a list. When iteration terminates, the list is returned.

 

Example:

In this example listloop enumerates the list (1 2 3 4 5) where each element will be multiplied by 2 with om*. Then each result will be collected by listing then returned as a list. The output of this loop is:

? OM->(2 4 6 8 10)

The equivalent patch using accumulator will be:

The binary function x-append collects all the results in a list.

 

accumulator (acum)

(accumulator accum init fun &optional retard )

[generic-function]

Input

accum any type of data

init data type applying to the first argument of fun

fun binary symbol , Lambda-function

Ouputs (from left to right)

- The first output triggers a collection and adds an element to the resulting list

- The second output returns the current state of the collection without triggering the evaluation, and without adding any element to that collection

- The third output reinitialize the collector, returning the initial value <init>

accumulator is the most general collector of omloop. The first input <accum> gets an iterator. The second input <init> assigns to the collector its initial state. The arguments of these inputs must comply with the binary Lambda-function's type of data. The arguments of this Lambda-function will correspond respectively to the initial state variable <init> (first input) and to <accum>'s value (second input).

The final internal state of accumulator will be the last operation of <fun> which will be returned through its second output.

Examples:

This omloop performs the cumulative sum of the values of <accum> at each iteration:

The patch returns:

? OM->10

The table below shows accumulator's processing of data and internal status through each step of iteration:

Step listloop output

Value of the

first input of accumulator

Value of the second input of

accumulator

Internal state Binary function "+" output
0 1 1 0 0 1
1 2 2 / 1 3
2 3 3 / 3 6
3 4 4 / 6 10
10

 

 

The value of the internal state of the collector after iteration is terminated is10.

Another example showing explicitly iteration through nesting. Here the binary Lambda-function is the standard lisp function list:

The output of this patch is a list with four levels of depth:

? OM->((((nil 1) 2) 3) 4)

 

The table showing accumulator's processing of data and internal status through each step of iteration:

Step

listloop output

Value of the first input of accumulator

Value of the second input of accumulator

Internal state

Binary function "list" output

0

1

1

nil

nil

(nil 1)

1

2

2

/

(nil 1)

((nil 1) 2)

2

3

3

/

((nil 1) 2)

(((nil 1) 2) 3)

3

4

4

/

(((nil 1) 2) 3)

((((nil 1) 2) 3) 4)

((((nil 1) 2) 3) 4)

 

This last example shows the use of accumulator for building a series approaching the number of Pi. To calculate a certain approximation of Pi we will use this series:

2 = 6 ( 1/1^2 + 1/2^2 + 1/3^2 + 1/4^2 +...)

This formula is due to the French mathematician JacquesBernouilli (1654-1705).

We will first use accumulator with an patch in lambda mode allowing us to collect a three-arithmetic-iterative-computation (addition, division and power-of), which is a custom Lambda-function:

This Lambda-function will be connected to the third input of accumulator:

From the second output of accumulator where the final state of collection is returned, the result will be multiplied by 6.0 in order to get a floating-point number. Then again the square root operation is applied to that last result to get Pi.

Notice that in the second input of accumulator the initial value is one. Zero would have caused a "division by zero" error.

The first input <accum> will receive the forloop iterator stepping iteration. The more steps of iteration, the closer the result will be to Pi. With 500 iterations, omloop returns:

? OM->3.139684123138722

With 5000 steps, the result becomes more accurate:

? OM->3.141401680950935

Note:

The purpose of this example is to demonstrate the handling of a patch in lambda mode with accumulator. Otherwise If the user wants to get pi number, it would be better to use this function:

returning:

? OM->3.141592653589793

 

Outputs

 

 

loopdo (eachTime)

(loopdo patch &rest oppatch )

[generic-function]

Input

patch any data type

Optional inputs

oppactch any data type

loopdo (eachTime) triggers iteration. This module can be extended adding outputs to loop.

 

finaldo (finally)

(finaldo patch &rest oppatch )

[generic-function]

Input

patch any data type

Optional inputs

oppactch any data type

finaldo returns the final internal state of the loop. This module can be extended, adding outputs to loop.