greek-letter-lambda-clip-artIn my last tutorial, I left you with an exercise, where you were supposed to set the «value» of the [foo1] node to the entire node of [foo2]. Here is one solution;

_data
  foo1:bar1
  foo2:bar2
set:@/../*/_data/*/foo1/?value
  source:@/../*/_data/*/foo2/?node

As you can see when you execute this pf.lambda code, what was previously «bar1», has now turned into the entire node of [foo2]. One crucial thing to realize, is that the [foo1] node, now has a «type declaration» between its name and its value. This is the part that says «node», between the colons on line two, in the pf.lambda result pane, at the bottom of your screen. This is because the value of [foo1] is no longer a simple string, but in fact a complex type of type «node» in itself.

Hyperlisp, and pf.lambda, both have support for types. By default, Hyperlisp supports most of the native types from the System namespace in .Net or Mono, but the type system in Hyperlisp is also extendible. This means that you can create your own types, and as long as your types can be converted into a string representation somehow, you can declare instances of these types in Hyperlisp. If you do, then the type declaration can be found in between the «name» parts of your node, and its «value» parts. Consider the following code;

_data:555

The above simple piece of node, declares a node who’s name is [_data], and who’s value is the string «555». If you wish to make sure that pf.lambda treats your value as an integer value, instead of a string, you must put «int» in between your node’s name and its value, like this;

_data:int:555

This sets Hyperlisp apart from JSON, and makes it more similar to BSON in fact. If you use the above [_data] node’s value as a source for an expression, then the type of your value will follow along when setting another node’s value, to become the value of your [_data] node. Let’s try;

_data:int:555
_result
set:@/-/?value
  source:@/../*/_data/?value

As you can see, the [_result] node now contains a type declaration, in addition to the value of «555», informing the pf.lambda execution engine, and the Hyperlisp parser, that this is an integer value, and not just a string

Please notice that only «value» parts of your node hierarchy can contain types. If you changed the above source expression to become «?name», then the integer value of «555» would be converted into its string representation. Only «value» parts of your tree can contain complex types. Name can never by anything besides strings.

Conversion between types

If you were to perform a comparison between the string «555» and the integer value of «555», then your comparison would not yield true. This creates a need to convert between types every now and then. Imagine you have a string value of «555», and you wish to convert that string value to become its associated integer value. The way you’d do this, is by appending the type you wish to convert to, after your expression de-referencing the node’s value, after the «expression type declaration», with a period between the expression’s type declaration, and the type you wish to convert your expression’s value to. Consider this;

_data:555
_result
set:@/-/?value
  source:@/../*/_data/?value.int

We have now converted the string value from [_data] to an integer value, and put the results of that conversion into the [_result] node. Using this technique, you can convert any expression’s value, to become any type you wish, as long as a conversion is somehow legally possible.

Multiple source nodes

Every now and then you have a list of nodes, who’s values, nodes or names combined, is what you’re looking for, where you wish to combine the results of an expression, to become the value, node or name for another node. Luckily this is an integral feature of the [set] statement, and is easily allowed, without any loops, or complicating pieces of code. Consider this;

_data
  source1:su
  source2:cc
  source3:ess
_result
set:@/-/?value
  source:@/../*/_data/*/?value

The [_result] node of the above pf.lambda statements, should after execution show you a combined result of «success», in the value of your [_result] node. This allows you to use multiple sources, which you create a single value out of, and set into your destination(s), using the [set] statement. This is often useful for concatenating strings, or other pieces of values, to create one single result

However, if all you wish to to, is to concatenate strings, and you know all the strings when you create your [set] statement, you can also use «formatting expressions». Formatting expressions are like string.Format from C#, consider the following code;

_data
  source1:su
  source2:cc
  source3:ess
_result
set:@/-/?value
  source:{0}{1}{2}
    :@/../*/_data/0/?value
    :@/../*/_data/1/?value
    :@/../*/_data/2/?value

As you can see in your result pane, the above code created the same result as our previous piece of code, making the value of [_result] become «success». By using formatting expressions, you can easily concatenate strings together, creating a combined value. You can also put constant values inside of your formatting expressions. Try putting «-error-» in between your first formatting value, and your second formatting value, in the source node’s value for instance, like this;

_data
  source1:su
  source2:cc
  source3:ess
_result
set:@/-/?value
  source:{0}-error-{1}{2}
    :@/../*/_data/0/?value
    :@/../*/_data/1/?value
    :@/../*/_data/2/?value

This way you can create strings, combined from multiple static, or dynamic sources, exactly as you see fit.

Relative source

The [set] statement also have support for using a «relative source». A relative source, is a source that is relative to its associated destination expression. This allows you to change a node set easily, such that the updated node set contains new values, names or nodes, that can be found relative to each node in its destination expression. Consider the following code;

_data
  foo1:bar1
  foo2:bar2
set:@/../*/_data/*/?value
  rel-source:@?name

We have now changed the «value» of all nodes inside of our [_data] node, to become the «name» of themselves. This is because the [set] statement will iterate all destinations, then use our [rel-source] expression, relative to the currently iterated destination, to extract the result, it uses as the new «value» for each destination.

Exercise time

In this exercise, I want you to «guess» what the code below will produce, before you execute it;

_data
  foo1:bar1
    foo1_child:Howdy
  foo2:bar2
    foo2_child:World
set:@/-/*/?value
  rel-source:@/*/?node.string
set:@/-2/*/*/?node

DO NOT EXECUTE the above code!!

Pay particularly attention to our last [set] statement here, and try to figure out what it will do, in addition to our [rel-source] [set] statement above, and see if you can use your intuition, logical and analytically skills, to «guess» how the entire node tree will look like, before you execute the above pf.lambda statements, and check your result.

Thank you for reading, have a nice day 🙂

Solution to above exercise

First of all, if you don’t give you [set] statements neither a source, nor a rel-source, then this sets whatever you’re trying to set in your [set] statement to null. For a ?node type of expression, this means that the node will be removed from the execution tree, in its entirety. That’s why our last [set] statement above, completely removes both the [foo1_child] node, and the [foo2_child] node

In addition, our [rel-source] above, will use all children nodes of every destination node, and convert the entire node to its string representation, making the value of both [foo1] and [foo2] become «foo1_child:Howdy» and «foo2_child:World».