Lambda Function Handling#

L - Define Lambda Function#

Defines a lambda function. The argument is not processed until the lambda function is executed, either via ${[func], [arg 1], ...}, or explicit execution $!{[func], [arg 1], ...}. The latter has to be used, if the function is itself a lambda argument.

import ison

dicData = {
    "__func_locals__": {
        "func": "$L{Hello %0}"
    },

    "result": "${func, Christian}"
}

dicResult = ison.run.Run(xData=dicData)
print(ison.run.ToString(dicResult))
{
    "result": "Hello Christian"
}

L* - Convert Structure to Lambda Function#

If the element that should become a lambda function is a dictionary or a list, you need to use this function.

import ison

dicData = {
    "__func_locals__": {
        "def_func": {
            "a": "Hello %0"
        },
        "func": "$L*{def_func}"
    },

    "result": "${func, Christian}"
}

dicResult = ison.run.Run(xData=dicData)
print(ison.run.ToString(dicResult))
{
    "result": {
        "a": "Hello Christian"
    }
}

Note that this can also be achieved using the __lambda__ tag inside the dictionary.

import ison

dicData = {
    "__func_locals__": {
        "func": {
            "__lambda__": {},
            "a": "Hello %0"
        }
    },

    "result": "${func, Christian}"
}

dicResult = ison.run.Run(xData=dicData)
print(ison.run.ToString(dicResult))
{
    "result": {
        "a": "Hello Christian"
    }
}

! - Explicit Lambda Function Execution#

If a lambda function wants to execute an argument again as lambda function, the explicit execution function $!{} has to be used.

import ison

dicData = {
    "__func_locals__": {
        "func_a": "$L{${%0, %1}}",
        "func_b": "$L{$!{%0, %1}}",
        "func_x": "$L{`%0, hello`}"
    },

    "result 1": "${func_a, $func_x, Christian}",
    "result 2": "${func_b, $func_x, Christian}"
}

dicResult = ison.run.Run(xData=dicData)
print(ison.run.ToString(dicResult))
{
    "result 1": "${$L{`%0, hello`}, Christian}",
    "result 2": "Christian, hello"
}

!foreach - Execute Lambda Function for Each Element#

!*{} is an alias of this function.

This processes a lambda function for each given argument and returns the result in a list.

import ison

dicData = {
    "__func_locals__": {
        "func": "$L{>%0<}",
    },

    "result": "$!foreach{$func, 1, 2}",
}

dicResult = ison.run.Run(xData=dicData)
print(ison.run.ToString(dicResult))
{
    "result": [
        ">1<",
        ">2<"
    ]
}

To execute a lambda function for each element of a list, you need to unroll the list.

import ison

dicData = {
    "__func_locals__": {
        "func": "$L{>%0<}",
    },

    "__locals__": {
        "lA": [1, 2, 3]
    },

    "result": "$!foreach{$func, *$lA}",
}

dicResult = ison.run.Run(xData=dicData)
print(ison.run.ToString(dicResult))
{
    "result": [
        ">1<",
        ">2<",
        ">3<"
    ]
}

This can also be combined with the $range{} function.

import ison

dicData = {
    "__func_locals__": {
        "func": "$L{>%0<}",
    },

    "__locals__": {
        "lA": [1, 2, 3]
    },

    "result": "$!foreach{$func, *$range{5}}",
}

dicResult = ison.run.Run(xData=dicData)
print(ison.run.ToString(dicResult))
{
    "result": [
        ">0<",
        ">1<",
        ">2<",
        ">3<",
        ">4<"
    ]
}

If a number of arguments should be passed to each instance of the lambda function execution, you can specify tuples as follows,

import ison

dicData = {
    "__func_locals__": {
        "func": "$L{%0: >%1< - %2}",
    },

    "result": "$!foreach{$func, (1, a, x), (2, b, y)}",
}

dicResult = ison.run.Run(xData=dicData)
print(ison.run.ToString(dicResult))
{
    "result": [
        "1: >a< - x",
        "2: >b< - y"
    ]
}

This is actually used by the function $enumerate{} to generate tuples of list indices with list elements:

import ison

dicData = {
    "__func_locals__": {
        "func": "$L{%0: >%1<}",
    },

    "__locals__": {
        "lA": [1, 2, 3]
    },

    "result": "$!foreach{$func, *$enumerate{$lA}}",
}

dicResult = ison.run.Run(xData=dicData)
print(ison.run.ToString(dicResult))
{
    "result": [
        "0: >1<",
        "1: >2<",
        "2: >3<"
    ]
}

In general, any number of lists can be combined to a list of grouped tuples using the $group{} function:

import ison

dicData = {
    "__func_locals__": {
        "func": "$L{%0: >%1< - %2}",
    },

    "__locals__": {
        "lA": ["a", "b", "c"],
        "lB": [1, 2, 3],
        "lC": ["x", "y", "z"]
    },

    "result": "$!foreach{$func, *$group{$lA, $lB, $lC}}",
}

dicResult = ison.run.Run(xData=dicData)
print(ison.run.ToString(dicResult))
{
    "result": [
        "a: >1< - x",
        "b: >2< - y",
        "c: >3< - z"
    ]
}

Named Arguments#

For lambdas with named parameters there is a slightly different syntax to iterate over a list of parameters. Note that you cannot mix named and positional lambda arguments in a $!foreach{} call.

import ison

dicData = {
    "__func_globals__": {
        "L_foo": {
            "__lambda__": {}, 
            "sKey": "%sKey%", 
            "iValue": "%iValue%"
        },
    },

    "__globals__": {
        "lKeys": ["a", "b", "c", "d"], 
        "lValues": [1, 2, 3],
    },

    "result": "$!foreach{$L_foo, sKey=*$lKeys, iValue=*$lValues}",
}

dicResult = ison.run.Run(xData=dicData)
print(ison.run.ToString(dicResult))
{
    "result": [
        {
            "sKey": "a",
            "iValue": 1
        },
        {
            "sKey": "b",
            "iValue": 2
        },
        {
            "sKey": "c",
            "iValue": 3
        }
    ]
}

You can also partially process with named arguments, which can be processed further at a later stage.

import ison

dicData = {
    "__func_globals__": {
        "L_foo": {
            "__lambda__": {}, 
            "sKey": "%sKey%", 
            "iValue": "%iValue%"
        },
    },

    "__globals__": {
        "lKeys": ["a", "b", "c", "d"], 
        "lValues": [1, 2, 3],
        "lPartial": "$!foreach{$L_foo, iValue=*$lValues}"
    },

    "result 1": "$lPartial",
    "result 2": "$!foreach{${lPartial:0}, sKey=*$lKeys}",
}

dicResult = ison.run.Run(xData=dicData)
print(ison.run.ToString(dicResult))
{
    "result 1": [
        "$L{$*{^{$S{sKey}: $S{%sKey%}, $S{iValue}: $S{$*{^1}}}}}",
        "$L{$*{^{$S{sKey}: $S{%sKey%}, $S{iValue}: $S{$*{^2}}}}}",
        "$L{$*{^{$S{sKey}: $S{%sKey%}, $S{iValue}: $S{$*{^3}}}}}"
    ],
    "result 2": [
        {
            "sKey": "a",
            "iValue": 1
        },
        {
            "sKey": "b",
            "iValue": 1
        },
        {
            "sKey": "c",
            "iValue": 1
        },
        {
            "sKey": "d",
            "iValue": 1
        }
    ]
}

If a number of unrolled lists of values are given, the number of iterations depend on the shortest list of values. However, if some named parameters are defined with single values, these values are repeated for all iterations.

import ison

dicData = {
    "__func_globals__": {
        "L_foo": {
            "__lambda__": {}, 
            "sKey": "%sKey%", 
            "iValue": "%iValue%"
        },
    },

    "__globals__": {
        "lKeys": ["a", "b", "c", "d"], 
        "iValue": 42
    },

    "result": "$!foreach{$L_foo, sKey=*$lKeys, iValue=$iValue}",
}

dicResult = ison.run.Run(xData=dicData)
print(ison.run.ToString(dicResult))
{
    "result": [
        {
            "sKey": "a",
            "iValue": 42
        },
        {
            "sKey": "b",
            "iValue": 42
        },
        {
            "sKey": "c",
            "iValue": 42
        },
        {
            "sKey": "d",
            "iValue": 42
        }
    ]
}

You can also directly specify a list value that for-each iterates over for a specific named argument, by using the tuple notation ().

import ison

dicData = {
    "__func_globals__": {
        "L_foo": {
            "__lambda__": {}, 
            "sKey": "%sKey%", 
            "iValue": "%iValue%"
        },
    },

    "__globals__": {
        "lKeys": ["a", "b", "c", "d"], 
        "iValue": 42
    },

    "result": "$!foreach{$L_foo, sKey=*$lKeys, iValue=(10, 23, 17, 49)}",
}

dicResult = ison.run.Run(xData=dicData)
print(ison.run.ToString(dicResult))
{
    "result": [
        {
            "sKey": "a",
            "iValue": "10"
        },
        {
            "sKey": "b",
            "iValue": "23"
        },
        {
            "sKey": "c",
            "iValue": "17"
        },
        {
            "sKey": "d",
            "iValue": "49"
        }
    ]
}

!where - Select with Lambda Condition#

!?{} is an alias of this function.

Executes lambda function for each argument. Those arguments where the lambda function return true or a non-zero scalar, are added to the resultant list of elements.

import ison

dicData = {
    "__func_locals__": {
        # Compare the element 'x' of the first lambda parameter with '1'
        # for equality. 
        "func": "$L{$eq{${%0:x}, 1}}",
    },

    "__locals__": {
        "lA": [
            { "x": 1, "y": "a" },
            { "x": 2, "y": "b" },
            { "x": 1, "y": "c" }
        ]
    },

    # Select only those elements of lA, where the 'x' element is 1
    "result": "$!where{$func, *$lA}",
}

dicResult = ison.run.Run(xData=dicData)
print(ison.run.ToString(dicResult))
{
    "result": [
        {
            "x": 1,
            "y": "a"
        },
        {
            "x": 1,
            "y": "c"
        }
    ]
}