Types and conversion
Types and conversion
These slots allow you to inspect and convert between Hyperlambda types, in addition to returning the vocabulary of slots your cloudlet understands.
How to use [types]
This slot returns all Hyperlambda types your current installation supports.
types
How to use [type]
This slot returns the Hyperlambda type name of some value.
.foo:int:57
type:x:-
After invoking the above, the value of [type] will be int.
How to use [convert]
This slot converts the value of an expression from its original type, to whatever [type] declaration you supply as its argument.
.foo:57
convert:x:-
type:int
Notice - You can also base64 encode and decode byte[] with this slot, by passing in “base64” or
“from-base64” as your [type] argument. The value of the object you want to convert must obviously support
conversion to the specified type, and will throw an exception if no conversion is possible, such as if you
for instance try to convert the string of “foo-bar” to an integer.
How to use [format]
This slot converts some expression or value according to some specified String.Format pattern.
The following code will string format the number 57 to make sure it’s prefixed with leading zeros, always ending
up having at least 5 digits. See .Net String.Format method for which patterns you can use. The culture used will
be the invariant one, unless you explicitly override the culture with a [culture] argument.
.foo:int:57
format:x:-
pattern:"{0:00000}"
To override the [culture] argument used you can use something such as follows.
.foo:decimal:57
format:x:-
pattern:"{0:0.00}"
culture:nb-NO
Since the above is using Norwegian Bokmal as its [culture] argument, it will return the result with a ,
as a decimal separator instead of the default which is .. You can use the same [pattern] values for
this slot as you can use in C# and .Net. To see an extensive list of for instance the formatting patterns you
can use for a date and time object, you can browse the Microsoft documentation
related to this. If you don’t supply a [culture] argument the invariant culture will be used.
How to use [int2words]
This slot takes a signed 64 bit integer and converts it to its word representation, such as for instance 1200050 becoming “one million two hundred thousand and fifty”. Below is an example of using the slot.
int2words:1200050
The slot works with signed 64 bit integer values, implying it can work with numbers in the trillions if required. The result of executing the above should resemble the following.
int2words:one million two hundred thousand and fifty
The slot is particularly useful for RAG and VSS databases, where embedding models such as “text-embedding-ada-002” tends to do a much better job at matching numbers if you spell these out instead of simply providing them as numbers.
How to use [vocabulary]
Returns the name of every static slot in your system, optionally passing in a string, or an expression leading to a string, which is a filtering condition, where the slot must start with the filter specified to be considered a part of the end result.
// Returns ALL slots in your system.
vocabulary
// Returns only slots starting with [io.file]
vocabulary:io.file
How to use [whitelist]
This slot temporarily within the given scope changes the available slots, allowing you to declare a block of lambda, where only a sub-set of your vocabulary is available for some piece of code to invoke. This allows you to relatively securely allow some partially untrusted source to pass in a piece of Hyperlambda, for then to allow it to evaluate its own Hyperlambda. The slot takes two arguments.
- [vocabulary] - Whitelisted slots
- [.lambda] - Lambda object to evaluate for the given scope
.result
whitelist
vocabulary
set-value
return
.lambda
// Inside of this [.lambda] object, we can only invoke [set-value], and no other slots!
set-value:x:@.result
.:foo
// Notice, the next line will throw an exception if you remove its "." character,
// because [add] is not whitelisted in our above [vocabulary] declaration!
.add:x:@.result
.
foo:bar
return
result:success
For security reasons the [whitelist] invocation’s [.lambda] object is immutable, and the caller cannot access nodes outside of the [.lambda] object itself, which prohibits the caller to modify, and/or read nodes from outside of its [whitelist] invocation. In addition a [whitelist] invocation creates its own result stack object, allowing the [whitelist] invocation to return values and nodes to the caller using for instance the [return] slot. If you execute the above Hyperlambda you can see how this semantically works by realizing how the above [.result] node never has its value actually changed, because our invocation to [set-value] inside our whitelist invocation yields a “null node-set result”. Hence, semantically the [whitelist] slot works the same way signaling a dynamic slot works in Hyperlambda, in that the invocation treats its [.lambda] object as if it was a dynamic slot, isolating it from the rest of our code, allowing the lambda object to return values and nodes to the caller.
How to use [context]
This slot allows you to add an object unto the stack, such that it can later be retrieved with the [get-context] slot. Below is an example.
.result
context:foo
value:bar
.lambda
set-value:x:@.result
get-context:foo
The slot requires a name as the value of its slot invocation node, a [value] as the value you want to put onto the stack, and a [.lambda] object being the lambda where the stack object exists, and can be retrieved using [get-context]. This is quite useful if you have some piece of data that needs to be accessible through the entirety of the execution of some Hyperlambda snippet, implying also for slots you invoke, where you don’t want to pass in the data as an argument to the slot itself. Imagine the following to understand how this works.
slots.create:bar
get-context:foo
return:x:-
context:foo
value:Context value
.lambda
signal:bar
If you execute the above Hyperlambda you will notice how the slot called [bar] actually has access to the context value called “foo”, and can retrieve this. This feature allows you to declare and create “long lasting arguments” that are accessible from within the entirety of a piece of Hyperlambda, including each slot it invokes, and/or Hyperlambda files it executes.
How to use [apply]
This slot takes an expression in addition to a list of arguments, and “applies” the arguments unto the expression’s result node set, allowing you to perform dynamic substitutions on lambda hierarchies such as the following illustrates.
.lambda
foo
arg1:{some_arg}
some-static-node:static-value
apply:x:-
some_arg:value of argument
After execution of the above Hyperlambda you will have a result resembling the following.
apply
foo
arg1:value of argument
some-static-node:static-value
Notice how the nodes from your template lambda object have been copied as children into your [apply]
node, while during this “copying process”, the arguments you supplied to [apply] have been used
to perform substitutions on all nodes in your template lambda having a value of {xxx}, where xxx is
your argument name. In the above example for instance the arg1:{some_arg} template node had its value
replaced by the value of the [some_arg] node passed in as a parameter to [apply]. If the name of
the argument to [apply], matches the value of your template node wrapped inside curly braces - Then
the value of your argument to apply becomes the new value of your template node after substitution has
been performed.
Only node values starting out with { and ending with } will be substituted, and you are expected to provide
all arguments found in the template lambda object, or the invocation will fail, resulting in an exception. This
allows you to create “template lambda objects” that you dynamically transform into something else, without
really caring about its original structure, but rather only its set of dynamic substitution arguments. This
slot leaves all other nodes as is.
Basically, the way it works, is that it takes your expression, and recursively iterates each node below the
result of your expression, checks to see if the node’s value is an argument such as e.g. {howdy} -
And if so, it substitutes the {howdy} parts with the value of the argument you are expected to supply to your
invocation having the name [howdy].
You can also reference the same argument multiple times in your template, in addition to create arguments that are lambda objects instead of simple values. Below is an example of both of these constructs.
.lambda
foo
foo1:{arg1}
foo2:{arg1}
foo3:{arg2}
apply:x:-
arg1:int:5
arg2
this:is
an:entire
lambda:object
used_as_an_argument:int:7
The above will result in the following.
apply
foo
foo1:int:5
foo2:int:5
foo3
this:is
an:entire
lambda:object
used_as_an_argument:int:7
Above you can also see how typing information is not lost, since the [foo1] and [foo2] nodes are both having integer values of 5 after apply is done executing. At the same time you can see how the [foo3] node instead of having a simple value applied, actually ended up with a copy of all children passed in as [arg2]. You can also substitute names of nodes, such as the following illustrates.
.lambda
foo
{arg1}:value-is-preserved
apply:x:-
arg1:foo1
The above of course results in the following.
apply
foo
foo1:value-is-preserved
This is a fairly advanced slot, but it’s the heart of the generator, allowing us to generate HTTP endpoints, starting out with some template file, which is dynamically changed, according to input arguments supplied during the crudification process. You can also combine transformations of names, values, and children in the same template nodes. The process is also recursive in nature, performing substitutions through the entire hierarchy of your template lambda.
How to use [sort]
Sort takes an expression leading to a list of nodes, in addition to a lambda object. Your lambda object will be invoked several times, with an [.lhs], an [.rhs] and a [.result] argument. It is your code’s responsibility to set the value of the [.result] node according to which of the [.lhs] and [.rhs] node should come first in the sorted result.
.data
.
name:Thomas
.
name:John
.
name:Jane
.
name:Peter
sort:x:@.data/*
if
lt:x:@.lhs/#/*/name
get-value:x:@.rhs/#/*/name
.lambda
set-value:x:@.result
.:int:-1
else-if
mt:x:@.lhs/#/*/name
get-value:x:@.rhs/#/*/name
.lambda
set-value:x:@.result
.:int:1
else
set-value:x:@.result
.:int:0
Notice, [sort] does not modify the original list, but returns a new list of nodes after having executed.