val org.eclipse.xtext.xbase.lib.*
// imports the Functions object. This is the base object of a lambda
val Functions$Functions Foo = [ String s |
// a lambda is a global variable like any other. By using val as opposed to various we are saying
// that Foo is final and cannot be reassigned. If you try to have a line that starts with "Foo =" you
// will get an error.
// Next you will see Functions. This is the root object of a lambda. Then you have $ which
// is a way to reference a subclass of Functions. Finally there is Function1. This is the subclass
// and the important part is the 1. This numbe must match the number of arguments the lambda
// will accept. You can have up to 7.
// The [ denotes the start of a lambda. You may have seen these square brackets before in
// timers and forEach. Those are lambds too. The only thing we are doing differently here is
// we are giving the lambda a name so it can be reused.
// Immediately after the bracket you list your arguments. In this cas we have only one and it
// is a String.
logInfo ("lambda", s)
// All this lambda does is log the passed in argument. You can do almost anything in a
// lambda t b at you can do in a rule.however, the lambda has no context so if you need
// to reference global vars or vals or rule local vars and vals you must pass them to the
// lambda as an argument.
]
// The closing bracket denotes the end of the lambda
...
// somewhere in a rule
Foo.apply ("bar")
// to call a lambda use its name followed by apply and the arguments in parens.
It doesn’t get any simpler than that I’m afraid.
The example creates a separate timer for each relay and stores them in a Map using the passed in String as the key. While it is a common way to keep track of a bunch of timers, it is not related to the lambda syntax. It is declared right at the beginning because it is a global val. But like I said above, the lambda doesn’t see globals so this Map is passed in as the third argument.
I mostly addressed this above. The key part is yes, the number at the end denotes the number of arguments.
Any object can be passed into a lambda. The class names follow a set pattern. Items are named TypeItem where Type is the Item Type you use in your .items file. E.g. SwitchItem, DimmerItem, NumberItem, GroupItem. If you don’t care that specifically, you can just use Item. Similarly states follow a similar pattern but instead use Type. E.g. DecimalType, OnOffType, etc.
The trick is, if you are using OH 1.x, figuring out the right import. Unfortunately these classes are scattered across several different packages. I’m on my poo hone right no so can’t easily look them up. I’ll try to come back tomorrow. In the mean time search “openhab SwitchType” and one of the hits will be the actual source code on github. The top line of actual code will start with “package”. That is what you need to import. OH 2 imports them for you.
A named lambda is a global val lIke any other. As such it must be at the top of a rules file before the actual rules. Only rules in that file will be able to call it.
They are global to to the file only, just like your other global vals and vars. You can and probably already have made local lambdas. Every time you create a timer or do a forEach or filter or other places where you have used square brackets with the | you have been creating a local lambda. You just haven’t been giving them a name so you can refuse them. But if you wanted you could do
val Functions$Function timerBody = [| logInfo ("timer", "bar")]
createTimer (now.plusSeconds(10), timerBody )