greek-letter-lambda-clip-artOne of the really cool traits of pf.lambda expressions, compared to for instance LINQ, is that they are dynamic in nature, and can be composed during run-time, without needing any compilation processes, or other static problems like LINQ implies. In addition, you can parametrize your pf.lambda expressions, using “formatting expressions”, to create child expressions, substituting parts of your main pf.lambda expressions. Consider this piece of code;

_data
  foo1:success
  foo2:error
pf.console.write-line:@/../*/{0}/*/foo1?value
  :_data

The above code will evaluate the “{0}” parts first, resulting in substituting “{0}” with “_data”. Hence, after evaluation of the formatting expressions, the expression that is evaluated, becomes; “@/../*/_data/*/foo1?value”.

pf.lambda formatting expressions, are similar to string.Format from C# in those regards. Where you’d normally use string.Format from C#, you can use formatting expressions in pf.lambda. Notice though, that any formatting parameters, must exist directly underneath the node where they are referenced, in addition to having an empty name.

You can also have formatting expression parameters, be expressions by themselves. Consider this piece of code;

_data
  foo1:success
  foo2:error
pf.console.write-line:@/../*/{0}/*/foo1?value
  :@/../0?name

In the above piece of code, the formatting parameter sent into the first expression, is an expression in itself, and will be evaluated before substitution occurs.

You can also nest formatting expressions. Consider the following piece of code;

_data
  foo1:success
  foo2:error
pf.console.write-line:@/../*/{0}/*/{1}?value
  :@/{0}/0?name
    :..
  :@/../*/_data/0?name

The above code will recursively format the original [pf.console.write-line] expression at line 4. Ending in the final expression being that of; “@/../*/_data/*/foo1?value”.

Ancestor iterators and parent iterators

We’ve used the “parent iterator” extensively already, but we haven’t formally defined it yet. The parent iterator, retrieves the parent node of whatever existing result-set you’re currently at. Consider this code;

_data
  foo1:success
    foo2:error
      foo3:error
pf.console.write-line:@/../0/0/0/0/./.?value

The above piece of code, basically first traverses down to the “foo3” node. Then it traverses back up again, twice, because of our “.” iterators. And as you can probably guess, the above piece of code produces the result of “success” being written to the console, if you run it through “lambda.exe”.

The “named ancestor iterator”, allows you to access a named ancestor, with one single iterator, and is defined as “..xxx”, where “xxx” is the name of the ancestor node you’re looking for. Consider this;

_data
  foo1:success
    foo2:error
      foo3:error
pf.console.write-line:@/../0/0/0/0/..foo1?value

The above code, does the same as our previous sample, except using the “named ancestor iterator”.

Boolean Hyper-dimensional Algebraic Graph objects expressions

Puuh. That sentence is a mouthful! But actually, the above sentence is the accurate scientific name of these features of pf.lambda expressions.

As we’ve already touched upon, you can use logical boolean algebraic operations on pf.lambda expressions. Below is an example of how to use the “AND” operator (|);

_data
  john:doe
  jane:doe
  john:hansen
  thomas:hansen
pf.console.write-line:@/../*/_data/*/(/john&/=doe)?node

The above piece of code, will basically match all children nodes from [_data] having both their name being “john” and their value being “doe”. To understand how it works, try to exchange the “&” character above with the “|” character, to use an “OR” operator instead.

Then when you have compared your results, exchange the operator to “^”, meaning “XOR”, for then to finally exchange it with “!”, meaning “NOT”. And compare your findings.

Basically, to condense;

  • “OR” means; “matching iterators on either side of |”
  • “AND” means; “match both sides of &”
  • “XOR” means; “match any side, but not both sides of ^”
  • “NOT” means; “remove anything matching right side of !”

These are the four basic boolean algebraic operators in pf.lambda expressions, and combining them together, allows you to intersect your pf.lambda tree-structures, in a “hyper-dimensional manner”, to create new dimensions through your tree structures.

An important thing to notice, is that when using boolean algebraic operators in your expressions, then your sub-expressions must somehow match the same result set. It is useless “NOT”‘ing out nodes from one part of your tree, with nodes from a completely different part of your tree.

Another thing to notice, is that it is also often useful to combine your boolean algebraic operators with “sub-expressions”, using parentheses. This allows you to create multiple sub-expressions, inside of parentheses, separating them by any boolean algebraic operator, having them all iterate on the same “outer nodes”, from their parent group, or root expression.

If your expressions becomes very complex, which they might, when using several groups, and boolean algebraic operators, you can always break them down on multiple lines, like this;

_data
  foo1:error
  foo2:success
pf.console.write-line:@"@/..
  /*
    /_data
      /*
        /foo1?value"

Above is an example of how to break down an expression, such that it spans multiple lines. If you want to know exactly how that works, feel free to watch the video below;