In this post, I would like to share interesting insights about recursion support in DMN and highlights how specific properties of the FEEL language enable functional programming constructs to be modeled in DMN.
We are going to start from a basic example, in order to demonstrate how the Business Friendliness nature of the FEEL language and DMN constructs, allow us to tame an otherwise commonly unpleasant problem: the definition of a recursive function. Then, we are going to adventure in FP land, and in the cradle of FEEL/DMN we will admire one of the best creatures of functional construct: the Y Combinator. At the end, we will find ourselves be asked the famous question again:
Using the pure engineering approach, letโs dig into the matter right away!
Basic recursion example
The Drools DMN open source engine allows recursion support in DMN Business Knowledge Model nodes. This enables modeling of recursive functions very easily and it is our recommended approach when modeling recursive functions in DMN: allow the function to call itself by its name.
Letโs take a look at a simple example: modeling the factorial function in DMN.
We can use the Kogito DMN editor and define the DRD as follows:
With the โfacโ Business Knowledge Model (in short, BKM) node defining the actual Factorial function recursively as:
As we can notice, the function invokes itself as any other normal
recursive function, the only difference here is that it is defined as part of a DMN Boxed Expression; the name of this function is defined by the BKM node with the boxed expression construct โfacโ, then the body of the function make reference and invokes itself as part of the FEEL expression โfac(n-1)โ.
We can use this BKM to calculate the actual result as passed by the Input Data node, as part of the โcompute factorialโ Decision, as:
This works well and gives the expected results:
{
My number: 3
fac: function fac( n )
compute factorial: 6
}
About currying
DMN and more importantly the FEEL language allow to define and invoke curried functions.
This allows us to write in FEEL something like:
{ f : function(a) function(b) a + b, r : f(1)(2) }
where:
- we defined a feel:context with 2 entries
- the first entry is named โfโ and defines a curried function: a function of one parameter โaโ that, once invoked, will return a function of one parameter โbโ that, once invoked, will return the sum of a+b
- the latter entry named โrโ which invokes the curried function with a=1 and b=2.
Albeit this is potentially a weird looking FEEL expression, we are not surprised once executed r = 3.
We can do equivalently by using DMN Boxed Expression constructs:
This is a BKM node named โcurried sumโ; it is a DMN Invocable of one parameter โaโ that, once invoked, will return a function of one parameter โbโ that, once invoked, returns the sum of a+b.
Again, we are not surprised once executed
curried sum(1)(2) = 3
Y Combinator: recursion without recursion support
Letโs go back for a moment to the earlier recursive function example; we overlooked the fact if itโs actually formally possible for a function to call itself by its name in DMN: the DMN specification does not explicitly support this, but it doesnโt explicitly forbid it either. In other terms, recursion support is not formally specified.
What-if we still needed to define a recursive function, but we found the road was still under construction, missing that formal recursion support? We can use a functional device, called the โY Combinatorโ which allows anonymous functions to achieve recursion without relying on self-invocation by its own (unexisting) name.
Letโs look at an example; we can define the Y Combinator in DMN as follows:
It is potentially a weird looking function :) letโs assume this was defined for us, and we can just make use of it.
We can use it to re-define the factorial calculation as:
We can notice the body of the โfacโ function definition is overall the same; however, this is not any longer a function invoking itself by its name: there is no trace of a call to โfac(โฆ)โ in the body of the function!
Naturally, there is still a form of recursion happening, but this time is leveraging the name of the parameters which are in scope of the closure: โfโ.
The result works as expected:
fac(3) = 6
We can take a look at another example, defining the Fibonacci sequence using the Y Combinator in DMN:
We notice again there is no call to โfib(โฆ)โ in the function body, yet recursion for the calculation of the Fibonacci sequence is performed thanks to the use of the Y Combinator.
Once again, the result works as expected:
fib(5) = [1, 1, 2, 3, 5]
For extra fun, we can re-define the Y Combinator using where possible the DMN Boxed Expression forms. This is an interesting exercise to see how closures are applied in their boxed variant. The Y Combinator definition could be refactored as:
and that would yield again the same expected and correct results.
For (extra (extra fun)), we can re-define once more the Y Combinator in a single FEEL expression to calculate for instance the factorial of 4:
{ Y: function(f) (function(x) x(x))(function(y) f(function(x) y(y)(x))), fac: Y(function(f) function(n) if n > 1 then n * f(n-1) else 1), fac4: fac(4) }.fac4
The result is unsurprisingly: 24.
Conclusion
In this post, we have seen a basic example of recursion in DMN, and how to leverage recursion support in the engine is very simple to use; engine recursion support is the approach we recommend to achieve recursion DMN: give the function a name, and in the body of the function make use of that name to invoke itself. In the example, we have named the function โfacโ, then we invoked โfac(โฆ)โ in the body of the function itself.
This approach is very practical, easy to model in DMN and works just fine.
We have also seen how DMN and FEEL do indeed support curried function definition and invocation. FEEL is (also) a functional language; all these properties allow us to define in DMN and use the Y Combinator, a functional device to achieve recursion without recursion support!
I personally found these exercises very interesting to apply functional programming concepts in DMN, while at the same time making sure the engine worked as expected. I would like to say special thanks to my colleagues Edoardo Vacchi and Luca Molteni for their support while discussing the Y Combinator and Currying functions.
Interested in DMN?
If you didnโt know about DMN before, you found this post interesting but looking for a gentle introduction to the DMN standard, we have just the right crash course on DMN, freely available for you at:
http://learn-dmn-in-15-minutes.com
Published on Java Code Geeks with permission by Matteo Mortari, partner at our JCG program. See the original article here: Functional Programming in DMN: it FEELs like recursing my university studies again Opinions expressed by Java Code Geeks contributors are their own. |
Thank you!
We will contact you soon.
Matteo MortariApril 17th, 2020Last Updated: April 14th, 2020

This site uses Akismet to reduce spam. Learn how your comment data is processed.