Lambda Functions#
Since the ISON processor is based on replacing objects with other objects, lambda-functions are right around the corner. There are basically three additional language features needed to implement lambda functions:
A \(\lambda\)-function scope is defined via
$L{}
.The parameters of a \(\lambda\)-function are denoted by
%[idx]
, where[idx]
is the parameter’s order index from left to right. For example,%0
is the first parameter,%1
the second, etc. You can also denote a parameter that is consumed by the function but not used, as%~[idx]
. For example, use%~0
to ignore the first parameter given. You may wonder what this feature could possibly be good for. Well, it is needed to implement \(\lambda\)-calculus.You can also defined named \(\lambda\)-function arguments with the syntax
%[name]%
.To execute a \(\lambda\)-function, i.e. replace the placeholders
%i
with specific parameters, you have two possibilities:explicit call via
$!{}
, orimplicit call via
${x, [arg 0], [arg 1], [named arg]=[value], [...]}
, wherex
is the reference to a \(\lambda\)-function.
The following examples will make the usage of \(\lambda\)-functions clearer.
Basic Usage#
The following example demonstrates the basic syntax. The element greet
is defined as a \(\lambda\)-function in the global variable scope, so that we can access it directly via ${greet}
. The function argument is %0
. Whatever is passed to the function as first argument is placed at the position of %0
.
We execute the \(\lambda\)-function implicitly, by passing the arguments in the reference function ${}
.
import ison
dicData = {
"__globals__": {
"greet": "$L{Hello %0}",
},
"say": "${greet, Christian}",
}
dicResult = ison.run.Run(xData=dicData)
print(ison.run.ToString(dicResult))
{
"say": "Hello Christian"
}
You can also pass nothing at all, which replaces the corresponding positional argument with an empty string. This can also be helpful, if you have a lambda function without any parameters, which you just want to execute, for example to execute some random number generator.
import ison
dicData = {
"__globals__": {
"greet": "$L{Value%0: $rand.int{0,10}}",
},
"say": "${greet,}",
"again": "${greet, ` next`}"
}
dicResult = ison.run.Run(xData=dicData)
print(ison.run.ToString(dicResult))
{
"say": "Value: 7",
"again": "Value next: 9"
}
Alternatively, you can name the lambda function arguments with the syntax %[name]%
, as shown in this example.
import ison
dicData = {
"__globals__": {
"greet": "$L{Hello %who%}",
},
# You can use `` to pass everything within the back quotes as argument
"say": "${greet, who=` > Christian < `}",
}
dicResult = ison.run.Run(xData=dicData)
print(ison.run.ToString(dicResult))
{
"say": "Hello > Christian < "
}
Note that a \(\lambda\)-function text block is treated as a literal object until all arguments have been replaced by a function call. In the following example, the ${x}
is only replaced, once the \(\lambda\)-function is fully evaluated. Here is an example,
import ison
dicData = {
"__globals__": {
"x": "let's go",
"greet": "$L{`Hello %0, $x`}",
},
"say": "$greet",
"again": "${greet, Christian}",
}
dicResult = ison.run.Run(xData=dicData)
print(ison.run.ToString(dicResult))
{
"say": "$L{`Hello %0, $x`}",
"again": "Hello Christian, let's go"
}
Processing Lambda Arguments#
If a lambda argument is a data structure like a dictionary, you may want to process this further. Consider the following example,
import ison
dicData = {
"__func_globals__": {
"JustDict": "$L{%0}",
"AsString": "$L{%0:%1}",
"FromDict": "$L{${%0:%1}}",
},
"__locals__": {
"dicA": {
"a": 1,
"b": 2,
}
},
"result 1": "${JustDict, $dicA}",
"result 2": "${AsString, $dicA, b}",
"result 3": "${FromDict, $dicA, b}",
}
dicResult = ison.run.Run(xData=dicData)
print(ison.run.ToString(dicResult))
{
"result 1": {
"a": 1,
"b": 2
},
"result 2": "{\"a\": 1, \"b\": 2}:b",
"result 3": 2
}
JustDict
: since%0
is the only element of the lambda function, the string result of this function can be converted to a JSON object. Therefore, the result is the data structure passed as argument.AsString
: because the resultant string after replacing the lambda arguments cannot be converted to a JSON object, and there is no additional${}
structure that could be parsed, the result is the string created from%0
and%1
.FromDict
: because the resultant string after replacing the lambda arguments contains a${}
element, this element is parsed again. During processing of${}
the:
is interpreted as an element access control symbol and so the string representation of just the%0
lambda argument is converted to a JSON object, which is a dictionary. Then this dictionary is accessed with the content of%1
, which results in 2.
Lambdas of Lambdas#
The real power of \(\lambda\)-functions comes from the fact, that also \(\lambda\)-functions can be passed in as parameters and that they can be evaluated partially, resulting in a new \(\lambda\)-function.
import ison
dicData = {
"__func_globals__": {
"polite": "$L{my dear %0}",
"greeting": "$L{Hello %0}",
"greet_polite": "${greeting, $polite}",
},
"x": "${greeting, Christian}",
"say": "${greet_polite, Christian}",
}
dicResult = ison.run.Run(xData=dicData)
print(ison.run.ToString(dicResult))
{
"x": "Hello Christian",
"say": "Hello my dear Christian"
}
Dictionary Lambdas#
It is at times useful to have a whole dictionary that is regarded as a lambda function. That is, the result of the lambda function is a dictionary and the lambda paramters vary elements of that dictionary. Here is an example:
import ison
dicData = {
"__func_globals__": {
"L_Data": {
# This line declares this dictionary to be a lambda function.
# It does not need to be the first entry, but this makes it clearer.
# The content of the '__lambda_' should be a dictionary,
# which is currently ignored.
"__lambda__": {},
# The remainder is the content of the lambda function
"a": "$int{%0}",
"b": "%1"
}
},
"result": "${L_Data, 1, 2}"
}
dicResult = ison.run.Run(xData=dicData)
print(ison.run.ToString(dicResult))
{
"result": {
"a": 1,
"b": "2"
}
}
The lambda dictionary can also declare local and global variables or other lambda functions.
import ison
dicData = {
"__func_globals__": {
"L_Data": {
# This line declares this dictionary to be a lambda function.
"__lambda__": {},
# Variables declared within this dictionary
"__locals__": {
"dicData": "%0"
},
"a": "${dicData:%1}",
}
},
"__locals__": {
"dicA": {
"x": 1,
"y": 2
}
},
"result": "${L_Data, ${dicA}, x}"
}
dicResult = ison.run.Run(xData=dicData, bPrintWarnings=True)
print(ison.run.ToString(dicResult))
{
"result": {
"a": 1
}
}
List Lambdas#
Lists can also be declared as lambda functions, by making their first entry __lambda__
, as in this example:
import ison
dicData = {
"__func_globals__": {
"L_Data": [
# This line declares this dictionary to be a lambda function.
# For a list, this needs to be the first entry.
"__lambda__",
# The remainder is the content of the lambda function
"%1", "%0"
]
},
"result": "${L_Data, 1, 2}"
}
dicResult = ison.run.Run(xData=dicData)
print(ison.run.ToString(dicResult))
{
"result": [
"2",
"1"
]
}