Index  |  Related pages  |  Classes  |  Functions  |  Entities  |  Function Sets  |  Groups

Function set functional_support

ETA functions and functional constructs. more...


Function list

all Returns true if all the items in a given collection evaluate to true.
allp Returns true if all the parameters evaluate to true.
any Returns true if any of the items in a given collection evaluate to true.
anyp Returns true if any one of the parameters evaluate to true.
cascade Concatenate a set of callable items so to form a single execution unit.
choice Selects one of two alternatives depending on the evaluation of the first parameter.
dolist Repeats an operation on a list of parameters.
eval Evaluates a sequence in functional context.
filter Filters sequence using a filter function.
firstOf Returns the first non-false of its parameters.
floop Repeats indefinitely a list of operations.
iff Performs a functional if; if the first parameter evaluates to true, the second parameter is evaluated and then returned, else the third one is evaluated and returned.
lbind Creates a dynamic late binding symbol.
let Assigns a value to another in a functional context.
lit Return its parameter as-is
map Creates a new vector of items transforming each item in the original array through the mapping function.
max Picks the minimal value among its parameters.
min Picks the minimal value among its parameters.
reduce Uses the values in a given sequence and iteratively calls a reductor function to extract a single result.
times Repeats a sequence a determined number of times.
valof Calls callable items or returns non callable ones.
xmap Creates a new vector of items transforming each item in the original array through the mapping function, applying also filtering on undesired items.
xtimes Repeats a sequence a determined number of times.

Detailed description

Falcon provides some special functional programming constructs that are known to the VM to have special significance. The vast majority of them starts a “functional evaluation” chain on their parameters before their value is evaluated. A functional evaluation is a recursive evaluation (reduction) of list structures into atoms. At the moment, the only list structure that can be evaluated this way is the array. Evaluating a parameter in functional context means that the given parameter will be recursively scanned for callable arrays or symbols that can be reduced to atoms. A callable array is reduced by calling the function and substituting it with its return value. When all the contents of the list are reduced, the higher level is evaluated.

Consider this example:

    function func0( p0, p1 ): ...
    function func1( p0 ): ...
 
    list = [func0, [func1, param1], param2]

Calling list as a callable array, func0 will be called with the array [func1, param1] as the first parameter, and param2 as the second parameter. On the other hand, evaluating the above list in a functional context, first func1 will be called with param1, then func0 will be called with the return value of the previous evaluation as the first parameter, and with param2 as the second parameter.

The functions in this section are considered “special constructs” as the VM knows them and treats them specially. Their definition overrides the definition of a functional evaluation, so that when the VM finds a special construct in its evaluation process, it ceases using the default evaluation algorithm and passes evaluation control to the construct.

In example, the iff construct selects one of its branches to be evaluated only if the first parameter evaluates to true:

    list = [iff, someValueIsTrue, [func0, [func1, param1]], [func1, param2] ]

If this list had to be evaluated in a functional context, then before iff had a chance to decide what to do, the two arrays [func0, ...] and [func1,...] would have been evaluated. As iff is a special construct, the VM doesn't evaluate its parameters and lets iff perform its operations as it prefer. In the case o iff, it first evaluates the first parameter, then evaluates in functional context the second on the third parameter, leaving unevaluated the other one.

Not all constructs evaluates everything it is passed to them in a functional context. Some of them are meant exactly to treat even a callable array (or anything else that should be reduced) as-is, stopping the evaluation process as the VM meets them. The description of each construct explains its working principles, and whether if its parameters are evaluated or not.

Please, notice that “callable” doesn't necessarily mean “evaluable”. To evaluate in functional context a callable symbol without parameter, it must be transformed into a single-element array. In example:

    function func0(): ...
 
    result = [iff, shouldEval, [func0], func0]

This places in result the value returned by func0 if shouldEval is true, while it returns exactly the function object func0 as-is if shouldEval is false.

A more formal definition of the funcional programming support in Falcon is provided in the Survival Guide.


Functions

all()

Returns true if all the items in a given collection evaluate to true.

all( sequence )
sequence

A sequence of arbitrary items.

Returns:

true if all the items are true, false otherwise

Items in sequence are evaluated in functional context for truth value. This means that, if they are sigmas, they get sigma-reduced and their return value is evaluated, otheriwise they are evaluated directly.

Truth value is determined using the standard Falcon truth check (nil is false, numerics are true if not zero, strings and collections are true if not empty, object and classes are always true).

The check is short circuited. This means that the processing of parameters is interrupted as an element is evaluated into false.

If the collection is empty, this function returns false.

allp()

Returns true if all the parameters evaluate to true.

allp( ... )
...

An arbitrary list of items.

Returns:

true if all the items are true, false otherwise

This function works like all, but the collection may be specified directly in the parameters rather being given in a separate array. This make easier to write allp in callable arrays. In example, one may write

       [allp, 1, k, n ...]

while using all one should write

       [all, [1, k, n ...]]

Parameters are evaluated in functional context. This means that, if they are sigmas, they get sigma-reduced and their return value is evaluated, otheriwise they are evaluated directly.

Truth value is determined using the standard Falcon truth check (nil is false, numerics are true if not zero, strings and collections are true if not empty, object and classes are always true).

If called without parameters, this function returns false.

any()

Returns true if any of the items in a given collection evaluate to true.

any( sequence )
sequence

A sequence of arbitrary items.

Returns:

true at least one item in the collection is true, false otherwise.

Items in sequence are evaluated in functional context for truth value. This means that, if they are sigmas, they get sigma-reduced and their return value is evaluated, otheriwise they are evaluated directly.

Truth value is determined using the standard Falcon truth check (nil is false, numerics are true if not zero, strings and collections are true if not empty, object and classes are always true).

The check is short circuited. This means that elements are evaluated until an element considered to be true (or sigma-reduced to a true value) is found.

If the collection is empty, this function returns false.

anyp()

Returns true if any one of the parameters evaluate to true.

anyp( ... )
...

A list of arbitrary items.

Returns:

true at least one parameter is true, false otherwise.

This function works like any, but the sequence may be specified directly in the parameters rather being given in a separate array. This make easier to write anyp in callable arrays. In example, one may write

       [anyp, 1, k, n ...]

while using any one should write

       [any, [1, k, n ...]]

Parameters are evaluated in functional context. This means that, if they are sigmas, they get sigma-reduced and their return value is evaluated, otheriwise they are evaluated directly.

Truth value is determined using the standard Falcon truth check (nil is false, numerics are true if not zero, strings and collections are true if not empty, object and classes are always true).

If called without parameters, this function returns false.

cascade()

Concatenate a set of callable items so to form a single execution unit.

cascade( callList, [...] )
callList

Sequence of callable items.

...

Optional parameters to be passed to the first callable item.

Returns:

The return value of the last callable item.

This function executes a set of callable items passing the parameters it receives beyond the first one to the first item in the list; from there on, the return value of the previous call is fed as the sole parameter of the next call. In other words,

       cascade( [F1, F2, ..., FN], p1, p2, ..., pn )

is equivalent to

       FN( ... F2( F1( p1, p2, ..., pn ) ) ... )

A function may declare itself “uninterested” to insert its value in the cascade by returning an out-of-band item. In that case, the return value is ignored and the same parameter it received is passed on to the next calls and eventually returned.

Notice that the call list is not evaluated in functional context; it is just a list of callable items. To evaluate the list, or part of it, in functional context, use the eval() function.

A simple example usage is the following:

       function square( a )
          return a * a
       end
 
       function sqrt( a )
          return a ** 0.5
       end
 
       cascade_abs = [cascade, [square, sqrt] ]
       > cascade_abs( 2 )      // 2
       > cascade_abs( -4 )     // 4

Thanks to the possibility to prevent insertion of the return value in the function call sequence, it is possible to program “interceptors” that will catch the progress of the sequence without interfering:

       function showprog( v )
          > "Result currently ", v
         return oob(nil)
       end
 
       // define sqrt and square as before...
       cascade_abs = [cascade, [square, showprog, sqrt, showprog] ]
       > "First process: ", cascade_abs( 2 )
       > "Second process: ", cascade_abs( -4 )

If the first function of the list declines processing by returning an oob item, the initial parameters are all passed to the second function, and so on till the last call.

In example:

       function whichparams( a, b )
          > "Called with ", a, " and ", b
          return oob(nil)
       end
 
       csq = [cascade, [ whichparams, lambda a,b=> a*b] ]
       > csq( 3, 4 )

Here, the first function in the list intercepts the parameters but, as it doesn't accepts them, they are both passed to the second in the list.

See also oob.

choice()

Selects one of two alternatives depending on the evaluation of the first parameter.

choice( selector, whenTrue, [whenFalse], [...] )
selector

The item to be evaluated.

whenTrue

The item to return if selector evaluates to true.

whenFalse

The item to be returned if selector evaluates to false

...

Optional parameters to be passed to the first callable item.

Returns:

The return value of the last callable item.

The selector parameter is evaluated in functional context. If it's a true atom or if it's a callable array which returns a true value, the ifTrue parameter is returned as-is, else the ifFalse parameter is returned. If the ifFalse parameter is not given and the selector evaluates to false, nil is returned.

The choice function is equivalent to iff where each branch is passed through the lit function:

       choice( selector, a, b ) == iff( selector, [lit, a], [lit, b] )

In case a literal value is needed, choice is more efficient than using iff and applying lit on the parameters.

dolist()

Repeats an operation on a list of parameters.

dolist( processor, sequence, [...] )
processor

A callable item that will receive data coming from the sequence.

sequence

A list of items that will be fed in the processor one at a time.

...

Optional parameters to be passed to the first callable item.

Returns:

The return value of the last callable item.

Every item in sequence is passed as parameter to the processor, which must be a callable item. Items are also functionally evaluated, one by one, but the parameter sequence is not functionally evaluated as a whole; to do that, use the explicit evaluation:

       dolist( processor, eval(array) )

This method is equivalent to xmap, but it has the advantage that it doesn't create an array of evaluated results. So, when it is not necessary to transform a sequence in another through a mapping function, but just to run repeatedly over a collection, this function is to be preferred.

eval()

Evaluates a sequence in functional context.

eval( sequence )
sequence

A sequence to be evaluated.

Returns:

The sigma-reduction (evaluation) result.

The parameter is evaluated in functional context; this means that if the parameter is a sequence starting with a callable item, that item gets called with the rest of the sequence passed as parameters, and the result it returns is considered the "evaluation result". This is performed recursively, inner-to-outer, on every element of the sequence before the call to the first element is actually performed.

The description of the functional evaluation algorithm is included in the heading of this section.

filter()

Filters sequence using a filter function.

filter( ffunc, sequence )
ffunc

A callable item used to filter the array.

sequence

A sequence of arbitrary items.

Returns:

The filtered sequence.

ffunc is called iteratively for every item in the collection, which is passed as a parameter to it. If the call returns true, the item is added to the returned array; if it returns false, the item is not added.

Items in the collection are treated literally (not evaluated).

firstOf()

Returns the first non-false of its parameters.

firstOf( ... )
...

Any number of arbitrary parameters.

Returns:

The first non-false item.

This function scans the paraters one at a time. Sigma evaluation is stopped, or in other words, every parameters is considered as-is, as if lit was used on each of them. The function returns the first parameter being non-false in a standard Falcon truth check. Nonzero numeric values, non empty strings, arrays and dictionaries and any object is considered true.

If none of the parameters is true, of is none of the parameter is given, the function returns nil (which is considered false).

floop()

Repeats indefinitely a list of operations.

floop( sequence )
sequence

A sequence of callable items that gets called one after another.

Every item in sequence gets executed, one after another. When the last element is executed, the first one is called again, looping indefinitely. Any function in the sequence may interrupt the loop by returning an out-of-band 0; if a function returns an out of band 1, all the remaining items in the list are ignored and the loop starts again from the first item.

Items in the array are not functionally evaluated.

iff()

Performs a functional if; if the first parameter evaluates to true, the second parameter is evaluated and then returned, else the third one is evaluated and returned.

iff( cfr, whenTrue, [whenFalse] )
cfr

A condition or a callable item.

whenTrue

Value to be called and/or returned in case cfr evaluates to true.

whenFalse

Value to be called and/or returned in case cfr evaluates to false.

Returns:

The evaluation result of one of the two branches (or nil).

Basically, this function is meant to return the second parameter or the third (or nil if not given), depending on the value of the first parameter; however, every item is evaluated in a functional context. This means that cfr may be a callable item, in which case its return value will be evaluated for truthfulness, and also the other parameters may. In example:

       > iff( 0, "was true", "was false" )           // will print “was false”
       iff( [lambda a=>a*2, 1] , [printl, "ok!"] )   // will print “ok!” and return nil

In the last example, we are not interested in the return value (printl returns nil), but in executing that item only in case the first item is true. The first item is a callable item too, so iff will first execute the given lambda, finding a result of 2 (true), and then will decide which element to pick, and eventually execute. Notice that:

       iff( 1 , printl( "ok!" ), printl( "no" ) )

This would have forced Falcon to execute the two printl calls before entering the iff function; still, iff would have returned printl return values (which is nil in both cases).

lbind()

Creates a dynamic late binding symbol.

lbind( name, [value] )
name

A string representing a late binding name.

value

A future binding value.

Returns:

A newly created late binding name.

This function create a late binding item which can be used in functional sequences as if the parameter was written in the source code prefixed with the amper '&' operator.

The following lines are equivalent:

       bound = lbind( "count" )
       ctx = &count

The return value of this function, both used directly or pre-cached, can be seamlessly merged with the & operator in functional sequences.

In example, it is possible to write the following loop:

       eval( .[
          .[ times 10 &count .[
             .[eval .[ printl 'Counting...' .[lbind 'count'] ] ]
             ]
          ]] )

It is also possible cache the value and use it afterwards:

       x = lbind( 'count' )
       eval( .[
          .[ times 10 &count .[
             .[ printl 'Counting...' x]
             ]
          ]] )

The value parameter initializes a future (forward) binding. Future bindings are bindings with a potential value, which is applied during function calls and symbol resolution to pre-existing symbolic entities. In practice, they allow calling fucntions with named parameters.

When mixing forward bindings and normal parameters, forward bindings are as placed directly at the position of the parameter they refer to, and they doesn't count during parameter expansion of non-named parameters. Also, they always overwrite the positional parameters, as they are considered after all the positional parameters have been placed on their spots.

       function test( par1, par2, par3 )
          >> "Par1: ", par1
          >> ", Par2: ", par2
          >  ", Par3: ", par3
       end
 
       x = lbind( "par2", "Hello" )
 
       test( x )                       // nil->par1, "Hello"->par2, nil->par3
       test( x, "Yo!" )                // "Yo!"->par1, "Hello"->par2, nil->par3
       test( "Yo!", x )                // as above
       test( "Yo!", "Yo! again", x )   // "Hello" overwrites "Yo again"
       test( x, "Yo!", "Yo! again", "end" )   // "Yo!"->par1, "Hello"->par2, "end"->par3

Note: lbind is not an ETA function.

let()

Assigns a value to another in a functional context.

let( dest, source )
dest

Destination value (passed by reference).

source

Source value.

Returns:

The assigned (source) value.

This function assigns a literal value given in source into dest, provided dest is a late binding or is passed by referece.

This function is an ETA and prevents evaluation of its first parameter. In other words, the first parameter is treadted as if passed through lit.

lit()

Return its parameter as-is

lit( item )
item

A condition or a callable item.

Returns:

The parameter unevaluated.

This function is meant to interrupt functional evaluation of lists. It has the same meaning of the single quote literal ' operator of the LISP language.

In example, the following code will return either a callable instance of printl, which prints a “prompt” before the parameter, or a callable instance of inspect:

       iff( a > 0, [lit, [printl, "val: "] ], inspect)( param )

as inspect is a callable token, but not an evaluable one, it is already returned literally; however, [printl, “val:”] would be considered an evaluable item. To take its literal value and prevent evaluation in functional context, the lit construct must be used.

map()

Creates a new vector of items transforming each item in the original array through the mapping function.

map( mfunc, sequence )
mfunc

A function or sigma used to map the array.

sequence

A sequence of arbitrary items.

Returns:

The parameter unevaluated.

mfunc is called iteratively for every item in the collection; its return value is added to the mapped array. In this way it is possible to apply an uniform transformation to all the item in a collection.

If mfunc returns an out of band nil item, map skips the given position in the target array, actually acting also as a filter function.

In example:

       function mapper( item )
          if item < 0: return oob(nil)  // discard negative items
          return item ** 0.5            // perform square root
       end
 
    inspect( map( mapper, [ 100, 4, -12, 9 ]) )    // returns [10, 2, 3]

See also oob.

max()

Picks the minimal value among its parameters.

max( ... )
...

The items to be checked.

Returns:

The smallest item in the sequence.

This function performs a lexicographic majority check on each element passed as a parameter, returning the greater of them.

A standard VM comparation is performed, so the standard ordering rules apply. This also means that objects overloading the (undefined) FBOM.compare method may provide specialized ordering rules.

If more than one item is found equal and greater than all the others, the first one is returned.

If the function is called without parameters, it returns nil.

min()

Picks the minimal value among its parameters.

min( ... )
...

The items to be checked.

Returns:

The smallest item in the sequence.

This function performs a lexicographic minority check on each element passed as a parameter, returning the smallest of them.

A standard VM comparation is performed, so the standard ordering rules apply. This also means that objects overloading the (undefined) FBOM.compare method may provide specialized ordering rules.

If more than one item is found equal and lesser than all the others, the first one is returned.

If the function is called without parameters, it returns nil.

reduce()

Uses the values in a given sequence and iteratively calls a reductor function to extract a single result.

reduce( reductor, sequence, [initial_value] )
reductor

A function or Sigma to reduce the array.

sequence

A sequence of arbitrary items.

initial_value

Optional startup value for the reduction.

Returns:

The reduced result.

The reductor is a function receiving two values as parameters. The first value is the previous value returned by the reductor, while the second one is an item iteratively taken from the origin array. If a startup value is given, the first time the reductor is called that value is provided as its first parameter, otherwise the first two items from the array are used in the first call. If the collection is empty, the initial_value is returned instead, and if is not given, nil is returned. If a startup value is not given and the collection contains only one element, that element is returned.

Some examples:

    > reduce( lambda a,b=> a+b, [1,2,3,4])       // sums 1 + 2 + 3 + 4 = 10
    > reduce( lambda a,b=> a+b, [1,2,3,4], -1 )  // sums -1 + 1 + 2 + 3 + 4 = 9
    > reduce( lambda a,b=> a+b, [1] )            // never calls lambda, returns 1
    > reduce( lambda a,b=> a+b, [], 0 )          // never calls lambda, returns 0
    > reduce( lambda a,b=> a+b, [] )             // never calls lambda, returns Nil

Items in the collection are treated literally (not evaluated).

times()

Repeats a sequence a determined number of times.

times( count, var, sequence )
count

Count of times to be repeated or non-open range.

var

A reference to a variable that will receive the current count, nil or a number.

sequence

A list of callable items that can be called one at a time.

Returns:

Last index processed.

This function is very similar to a functional for/in loop. It repeats a sequence of callable items in the sequence parameter a determined number of times, eventually filling a variable with the current loop index, or mangling the parameters of the given callable items so that they receive the index as a parameter.

Note: The paramters of times are not functionally evaluated.

The loop index count will be given values from 0 to the required index-1 if count is numeric, or it will act as the for/in loop if count is a range.

The way the current index loop is sent to the items depends on the type of var. If it's nil, then the count is only kept internally; Sigma functions in sequence may not need it, or they may use an internal counter. In example:

       function printTimes()
          static: i = 0
          > "Called ", ++i, " times."
       end
 
       times( 10, nil, [ printTimes ] )

If val is a reference to a variable, then that variable is updated to the current loop value. The Sigmas in sequence may receive it as a parameter passed by reference or may accesses it from the outer (global) scope. In example:

       // module scope
       sent = nil
 
       function printSent()
          global sent
          > "Called ", sent, " times."
       end
 
       function printParam( var )
          > "Parameter is... ", var
       end
 
       times( 10, $sent, [ printSent, [printParam, $sent] ] )

In the above example, printSent "fishes" the global value of sent, while printParam uses a reference to it in its parameters and sees its paramter list changed at each call.

Finally, var may be a number. If the number is zero or less, the loop variable is just appended to the parameters in the call. The following example prints a list of pair numbers between 2 and 10:

       times( [2:11:2],     // range 2 to 10+1, with step 2
          0,                // instruct times to add the loop index to the calls
          .[ .[ printl "Index is now..." ] ]      // the calls (just 1).
          )

If it's a positive number, then the nth element of the Sigmas in the list will be changed. In this last case, the items in sequence need not just to be callable; they must be Sigmas (lists starting with a callable item) having at least enough items for the var ID to be meaningful. The next example alters the parameter element #2 in the Sigmas array it calls:

       times( [2:11:2], 2,
          .[ .[ printl "Index is now... "
                  nil
                  " ..." ] ]
          )

Notice the "nil" at position 2 in the Sigma call of printl. It may actually be any item, as it will be changed each time before the sigma is called.

In this case, if the callable items in sequence are not sigmas, or if they are to short for the var ID to be useful, they get called without the addition of the loop index parameter.

Note: The original sigmas are not restored after times is executed in this modality. This means that the arrays in sequence will be altered, and they will hold the last number set by times before exit.

Exactly like floop, the flow of calls in times can be altered by the functions in sequence returning an out-of-band 0 or 1. If any function in the sequence returns an out-of-band 0, times terminates and return immediately (performing an operation similar to "break"). If a function returns an out-of-band 1, the rest of the items in sequence are ignored, and the loop is restarted with the index updated; this is equivalent to a functional "continue". In example:

    times( 10, 0,
       .[ (function(x); if x < 5: return oob(1); end)   // skip numbers less than 5
          printl // print the others
        ]
     )

The times function return the last generated value for the index. A natural termination of times can be detected thanks to the fact that the index is equal to the upper bound of the range, while an anticipated termination causes times to return a different index. In example, if count is 10, the generated index (possibly received by the items in sequence) will range from 0 to 9 included, and if the function terminates correctly, it will return 10. If a function in sequence returns an out-of-band 0, causing a premature termination of the loop, the value returned by times will be the loop index at which the out-of-band 0 was returned.

Note: Ranges [m:n] where m > n (down-ranges) terminate at n included; in that case, a succesful completion of times return one-past n.

valof()

Calls callable items or returns non callable ones.

valof( item )
item

The item to be checked.

Returns:

The item if it is not callable, or the call return value.

The name function is a short for extended value. It is meant to determine if the passed item is a non-callable value or if it should be called to determine a value. Performing this check at script level time consuming and often clumsy, and this function is easily used in functional sequences.

xmap()

Creates a new vector of items transforming each item in the original array through the mapping function, applying also filtering on undesired items.

xmap( mfunc, sequence )
mfunc

A function or sigma used to map the array.

sequence

A sequence to be mapped.

Returns:

The mapped sequence.

mfunc is called iteratively for every item in the collection; its return value is added to the mapped array. Moreover, each item in the collection is functionally evaluated before being passed to mfunc.

The filter function may return an out of band nil item to signal that the current item should not be added to the final collection.

In example:

 
       mapper = lambda item => (item < 0 ? oob(nil) : item ** 0.5)
       add = lambda a, b => a+b         // a lambda that will be evaluated
 
       inspect( xmap( mapper, [ [add, 99, 1], 4, -12, 9 ]) )    // returns [10, 2, 3]

See also oob, dolist.

xtimes()

Repeats a sequence a determined number of times.

xtimes( count, var, sequence )
count

Count of times to be repeated or non-open range.

var

A reference to a variable that will receive the current count, nil or a number.

sequence

A list of callable items that can be called one at a time.

Returns:

Last index processed.

This function is omologous to times, but it automatically evaluates each one of the items in the sequence list, as if they were all prefixed by an eval call.

See also times.


Index  |  Related pages  |  Classes  |  Functions  |  Entities  |  Function Sets  |  Groups
Made with Faldoc 1.0.0