When writing DataWeave code, it is common to use functions that take a lambda as parameter, such as
flatten. Using lambda in DataWeave is well documented and easy to understand for developers that already worked with functional programming in other languages.
However, creating a DataWeave function that accepts a lambda as parameter, while relatively easy, is not well documented in Mulesoft' documentation.
As creating functions taking lambda as parameters can be very useful, I will explain how to pass a lambda as parameter of a function. Common use cases are to accept a callback or apply a transformation or a predicate passed as a parameter.
In functional programming, data are immutable and thus cannot be modified. To change a value, we do not modify it directly. Instead, the value is processed and a new value defined.
%dw 2.0 var initialValue = 21 // Error: a variable cannot be modified after its declaration var newValue = 42 // Success: a new variable is created containing the new value. var newValue = 42 * 2
Arrays follow the same principle and their values cannot be modified. Instead, we will use functions that applies some behaviour to each element. This behaviour is defined in a lambda, a function without a name that can be saved in a variable or passed as a parameter.
%dw 2.0 var initialValue = [1, 2, 3] var newValue = initialValue map ((value) -> value * 2) newValue // [2, 4, 6]
In the example above,
(value) -> value * 2 is a lambda that takes the existing value and multiply it by 2. This function is passed as a parameter of map.
DataWeave allows a lambda to you anonymous parameters, and to be passed without being surrounded by variables. This shorten the code and can make it more clear. The following line does the same thing as its equivalent above:
var newValue = initialValue map $ * 2
For more information, refer to Mulesoft's documentation.
To write a function that accepts a lambda as parameter, you need two things:
- Define the parameter and type it so it is clear it accepts a lambda.
- Call the lambda and give it the required parameters.
To define and type the parameter, you must specify the parameter name and the signature of the function it accepts:
helloNewYear(lambda: (param1: String, param2: Number) -> String) = ...
In this example, we declare a function
helloNewYear that accepts one parameter: a lambda. This lambda should be a function accepting a String and a Number as parameter, and returning a String.
Once we have our parameter, we need to call it. It is called in the same way as any other function, taking the parameter name as function name:
helloNewYear(lambda: (param1: String, param2: Number) -> String) = lambda("Hello", 2022)
Now, we can call our function and pass it the lambda we want to execute:
helloNewYear((sentence, year) -> sentence ++ " " ++ year)
This will output "Hello 2022". Your lambda can contain any behaviour you wish to define.
%dw 2.0 // Processing function that takes a lambda as parameter fun updateEvenCharacters( str: String, // The type of the parameter is the expected signature of the lambda to call mapper: (str: String, num: Number) -> String ): String = str splitBy "" // The lambda is called as a normal function, with the parameter name being the function name map (if (isEven($$)) mapper($, $$) else $) joinBy "" output text/plain --- // Call the processing function and pass a lambda as second parameter updateEvenCharacters( "Hello World!", // The parameter should be the lambda to call. (value, index) -> upper(value) ++ index )