-
Notifications
You must be signed in to change notification settings - Fork 6
/
Copy pathprogramming.html
363 lines (352 loc) · 46.8 KB
/
programming.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
<!DOCTYPE html><html lang="en"><head><meta charSet="utf-8"/><meta http-equiv="X-UA-Compatible" content="IE=edge"/><title>Programming constructs · JSONata</title><meta name="viewport" content="width=device-width, initial-scale=1.0"/><meta name="generator" content="Docusaurus"/><meta name="description" content="So far, we have introduced all the parts of the language that allow us to extract data from an input JSON document, combine the data using string and numeric operators, and format the structure of the output JSON document. What follows are the parts that turn this into a Turing complete, functional programming language."/><meta name="docsearch:version" content="2.0.0"/><meta name="docsearch:language" content="en"/><meta property="og:title" content="Programming constructs · JSONata"/><meta property="og:type" content="website"/><meta property="og:url" content="http://docs.jsonata.org/"/><meta property="og:description" content="So far, we have introduced all the parts of the language that allow us to extract data from an input JSON document, combine the data using string and numeric operators, and format the structure of the output JSON document. What follows are the parts that turn this into a Turing complete, functional programming language."/><meta name="twitter:card" content="summary"/><link rel="shortcut icon" href="/img/jsonata-button.png"/><link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0/styles/default.min.css"/><script type="text/javascript" src="https://buttons.github.io/buttons.js"></script><script type="text/javascript" src="/js/jsonata-examples.js"></script><script src="/js/scrollSpy.js"></script><link rel="stylesheet" href="/css/main.css"/><script src="/js/codetabs.js"></script></head><body class="sideNavVisible separateOnPageNav"><div class="fixedHeaderContainer"><div class="headerWrapper wrapper"><header><a href="/"><img class="logo" src="/img/jsonata-button.png" alt="JSONata"/><h2 class="headerTitleWithLogo">JSONata</h2></a><a href="/versions"><h3>2.0.0</h3></a><div class="navigationWrapper navigationSlider"><nav class="slidingNav"><ul class="nav-site nav-site-internal"><li class="siteNavGroupActive"><a href="/overview" target="_self">Docs</a></li><li class=""><a href="http://try.jsonata.org" target="_self">Try</a></li><li class=""><a href="https://github.com/jsonata-js/jsonata" target="_self">GitHub</a></li><li class=""><a href="https://www.npmjs.com/package/jsonata" target="_self">NPM</a></li></ul></nav></div></header></div></div><div class="navPusher"><div class="docMainWrapper wrapper"><div class="docsNavContainer" id="docsNav"><nav class="toc"><div class="toggleNav"><section class="navWrapper wrapper"><div class="navBreadcrumb wrapper"><div class="navToggle" id="navToggler"><div class="hamburger-menu"><div class="line1"></div><div class="line2"></div><div class="line3"></div></div></div><h2><i>›</i><span>Language Guide</span></h2><div class="tocToggler" id="tocToggler"><i class="icon-toc"></i></div></div><div class="navGroups"><div class="navGroup"><h3 class="navGroupCategoryTitle">Getting Started</h3><ul class=""><li class="navListItem"><a class="navItem" href="/overview">Overview</a></li><li class="navListItem"><a class="navItem" href="/using-nodejs">In NodeJS</a></li><li class="navListItem"><a class="navItem" href="/using-browser">In a Web Page</a></li></ul></div><div class="navGroup"><h3 class="navGroupCategoryTitle">Language Guide</h3><ul class=""><li class="navListItem"><a class="navItem" href="/simple">Simple Queries</a></li><li class="navListItem"><a class="navItem" href="/predicate">Predicate Queries</a></li><li class="navListItem"><a class="navItem" href="/expressions">Functions and Expressions</a></li><li class="navListItem"><a class="navItem" href="/construction">Result Structures</a></li><li class="navListItem"><a class="navItem" href="/composition">Query Composition</a></li><li class="navListItem"><a class="navItem" href="/sorting-grouping">Sorting, Grouping and Aggregation</a></li><li class="navListItem"><a class="navItem" href="/processing">Processing Model</a></li><li class="navListItem navListItemActive"><a class="navItem" href="/programming">Functional Programming</a></li><li class="navListItem"><a class="navItem" href="/regex">Regular Expressions</a></li><li class="navListItem"><a class="navItem" href="/date-time">Date/Time Processing</a></li></ul></div><div class="navGroup"><h3 class="navGroupCategoryTitle">Operators</h3><ul class=""><li class="navListItem"><a class="navItem" href="/path-operators">Path Operators</a></li><li class="navListItem"><a class="navItem" href="/numeric-operators">Numeric Operators</a></li><li class="navListItem"><a class="navItem" href="/comparison-operators">Comparison Operators</a></li><li class="navListItem"><a class="navItem" href="/boolean-operators">Boolean Operators</a></li><li class="navListItem"><a class="navItem" href="/other-operators">Other Operators</a></li></ul></div><div class="navGroup"><h3 class="navGroupCategoryTitle">Function Library</h3><ul class=""><li class="navListItem"><a class="navItem" href="/string-functions">String Functions</a></li><li class="navListItem"><a class="navItem" href="/numeric-functions">Numeric Functions</a></li><li class="navListItem"><a class="navItem" href="/aggregation-functions">Aggregation Functions</a></li><li class="navListItem"><a class="navItem" href="/boolean-functions">Boolean Functions</a></li><li class="navListItem"><a class="navItem" href="/array-functions">Array Functions</a></li><li class="navListItem"><a class="navItem" href="/object-functions">Object Functions</a></li><li class="navListItem"><a class="navItem" href="/date-time-functions">Date/Time Functions</a></li><li class="navListItem"><a class="navItem" href="/higher-order-functions">Higher Order Functions</a></li></ul></div><div class="navGroup"><h3 class="navGroupCategoryTitle">Extending JSONata</h3><ul class=""><li class="navListItem"><a class="navItem" href="/embedding-extending">Embedding and Extending JSONata</a></li><li class="navListItem"><a class="navItem" href="/contributing">Community and Contributing</a></li></ul></div></div></section></div><script>
var coll = document.getElementsByClassName('collapsible');
var checkActiveCategory = true;
for (var i = 0; i < coll.length; i++) {
var links = coll[i].nextElementSibling.getElementsByTagName('*');
if (checkActiveCategory){
for (var j = 0; j < links.length; j++) {
if (links[j].classList.contains('navListItemActive')){
coll[i].nextElementSibling.classList.toggle('hide');
coll[i].childNodes[1].classList.toggle('rotate');
checkActiveCategory = false;
break;
}
}
}
coll[i].addEventListener('click', function() {
var arrow = this.childNodes[1];
arrow.classList.toggle('rotate');
var content = this.nextElementSibling;
content.classList.toggle('hide');
});
}
document.addEventListener('DOMContentLoaded', function() {
createToggler('#navToggler', '#docsNav', 'docsSliderActive');
createToggler('#tocToggler', 'body', 'tocActive');
var headings = document.querySelector('.toc-headings');
headings && headings.addEventListener('click', function(event) {
var el = event.target;
while(el !== headings){
if (el.tagName === 'A') {
document.body.classList.remove('tocActive');
break;
} else{
el = el.parentNode;
}
}
}, false);
function createToggler(togglerSelector, targetSelector, className) {
var toggler = document.querySelector(togglerSelector);
var target = document.querySelector(targetSelector);
if (!toggler) {
return;
}
toggler.onclick = function(event) {
event.preventDefault();
target.classList.toggle(className);
};
}
});
</script></nav></div><div class="container mainContainer docsContainer"><div class="wrapper"><div class="post"><header class="postHeader"><a class="edit-page-link button" href="https://github.com/jsonata-js/jsonata/edit/master/docs/programming.md" target="_blank" rel="noreferrer noopener">Edit</a><h1 id="__docusaurus" class="postHeaderTitle">Programming constructs</h1></header><article><div><span><p>So far, we have introduced all the parts of the language that allow us to extract data from an input JSON document, combine the data using string and numeric operators, and format the structure of the output JSON document. What follows are the parts that turn this into a Turing complete, functional programming language.</p>
<h2><a class="anchor" aria-hidden="true" id="comments"></a><a href="#comments" aria-hidden="true" class="hash-link"><svg class="hash-link-icon" aria-hidden="true" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Comments</h2>
<p>JSONata expressions can be interleaved with comments using 'C' style comment delimeters. For example,</p>
<pre><code class="hljs"><span class="hljs-comment">/* Long-winded expressions might need some explanation */</span>
(
<span class="hljs-symbol">$</span><span class="hljs-built-in">pi</span> := <span class="hljs-number">3.1415926535897932384626</span>;
<span class="hljs-comment">/* JSONata is not known for its graphics support! */</span>
<span class="hljs-symbol">$</span>plot := function(<span class="hljs-symbol">$</span>x) {(
<span class="hljs-symbol">$</span><span class="hljs-built-in">floor</span> := <span class="hljs-symbol">$</span>string ~> <span class="hljs-symbol">$</span>substringBefore(?, <span class="hljs-string">'.'</span>) ~> <span class="hljs-symbol">$</span>number;
<span class="hljs-symbol">$</span>index := <span class="hljs-symbol">$</span><span class="hljs-built-in">floor</span>((<span class="hljs-symbol">$</span>x + <span class="hljs-number">1</span>) * <span class="hljs-number">20</span> + <span class="hljs-number">0.5</span>);
<span class="hljs-symbol">$</span>join([<span class="hljs-number">0.</span>.<span class="hljs-symbol">$</span>index].(<span class="hljs-string">'.'</span>)) & <span class="hljs-string">'O'</span> & <span class="hljs-symbol">$</span>join([<span class="hljs-symbol">$</span>index.<span class="hljs-number">.40</span>].(<span class="hljs-string">'.'</span>))
)};
<span class="hljs-comment">/* Factorial is the product of the integers 1..n */</span>
<span class="hljs-symbol">$</span>product := function(<span class="hljs-symbol">$</span>a, <span class="hljs-symbol">$</span>b) { <span class="hljs-symbol">$</span>a * <span class="hljs-symbol">$</span>b };
<span class="hljs-symbol">$</span>factorial := function(<span class="hljs-symbol">$</span>n) { <span class="hljs-symbol">$</span>n = <span class="hljs-number">0</span> ? <span class="hljs-number">1</span> : <span class="hljs-symbol">$</span>reduce([<span class="hljs-number">1.</span>.<span class="hljs-symbol">$</span>n], <span class="hljs-symbol">$</span>product) };
<span class="hljs-symbol">$</span><span class="hljs-built-in">sin</span> := function(<span class="hljs-symbol">$</span>x){ <span class="hljs-comment">/* define sine in terms of cosine */</span>
<span class="hljs-symbol">$</span><span class="hljs-built-in">cos</span>(<span class="hljs-symbol">$</span>x - <span class="hljs-symbol">$</span><span class="hljs-built-in">pi</span>/<span class="hljs-number">2</span>)
};
<span class="hljs-symbol">$</span><span class="hljs-built-in">cos</span> := function(<span class="hljs-symbol">$</span>x){ <span class="hljs-comment">/* Derive cosine by expanding Maclaurin series */</span>
<span class="hljs-symbol">$</span>x > <span class="hljs-symbol">$</span><span class="hljs-built-in">pi</span> ? <span class="hljs-symbol">$</span><span class="hljs-built-in">cos</span>(<span class="hljs-symbol">$</span>x - <span class="hljs-number">2</span> * <span class="hljs-symbol">$</span><span class="hljs-built-in">pi</span>) : <span class="hljs-symbol">$</span>x < -<span class="hljs-symbol">$</span><span class="hljs-built-in">pi</span> ? <span class="hljs-symbol">$</span><span class="hljs-built-in">cos</span>(<span class="hljs-symbol">$</span>x + <span class="hljs-number">2</span> * <span class="hljs-symbol">$</span><span class="hljs-built-in">pi</span>) :
<span class="hljs-symbol">$</span><span class="hljs-keyword">sum</span>([<span class="hljs-number">0.</span><span class="hljs-number">.12</span>].(<span class="hljs-symbol">$</span><span class="hljs-built-in">power</span>(<span class="hljs-number">-1</span>, <span class="hljs-symbol">$</span>) * <span class="hljs-symbol">$</span><span class="hljs-built-in">power</span>(<span class="hljs-symbol">$</span>x, <span class="hljs-number">2</span>*<span class="hljs-symbol">$</span>) / <span class="hljs-symbol">$</span>factorial(<span class="hljs-number">2</span>*<span class="hljs-symbol">$</span>)))
};
[<span class="hljs-number">0.</span><span class="hljs-number">.24</span>].<span class="hljs-symbol">$</span><span class="hljs-built-in">sin</span>(<span class="hljs-symbol">$</span>*<span class="hljs-symbol">$</span><span class="hljs-built-in">pi</span>/<span class="hljs-number">12</span>).<span class="hljs-symbol">$</span>plot(<span class="hljs-symbol">$</span>)
)
</code></pre>
<p>Produces <a href="http://try.jsonata.org/ryYn78Q0m">this</a>, if you're interested!</p>
<h2><a class="anchor" aria-hidden="true" id="conditional-logic"></a><a href="#conditional-logic" aria-hidden="true" class="hash-link"><svg class="hash-link-icon" aria-hidden="true" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Conditional logic</h2>
<p>If/then/else constructs can be written using the ternary operator "? :".</p>
<p><code>predicate ? expr1 : expr2</code></p>
<p>The expression <code>predicate</code> is evaluated. If its effective boolean value (see definition) is <code>true</code> then <code>expr1</code> is evaluated and returned, otherwise <code>expr2</code> is evaluated and returned.</p>
<p><strong>Examples</strong></p>
<div class="jsonata-ex">
<div>Account.Order.Product.{
`Product Name`: $.Price > 100 ? "Premium" : "Basic"
}</div>
<div>[
{
"Bowler Hat": "Basic"
},
{
"Trilby hat": "Basic"
},
{
"Bowler Hat": "Basic"
},
{
"Cloak": "Premium"
}
]</div>
</div>
<h2><a class="anchor" aria-hidden="true" id="variables"></a><a href="#variables" aria-hidden="true" class="hash-link"><svg class="hash-link-icon" aria-hidden="true" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Variables</h2>
<p>Any name that starts with a dollar '$' is a variable. A variable is a named reference to a value. The value can be one of any type in the language's <a href="processing#the-jsonata-type-system">type system</a>.</p>
<h3><a class="anchor" aria-hidden="true" id="built-in-variables"></a><a href="#built-in-variables" aria-hidden="true" class="hash-link"><svg class="hash-link-icon" aria-hidden="true" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Built-in variables</h3>
<ul>
<li><code>$</code> The variable with no name refers to the context value at any point in the input JSON hierarchy. Examples</li>
<li><code>$$</code> The root of the input JSON. Only needed if you need to break out of the current context to temporarily navigate down a different path. E.g. for cross-referencing or joining data. Examples</li>
<li>Native (built-in) functions. See function library.</li>
</ul>
<h3><a class="anchor" aria-hidden="true" id="variable-binding"></a><a href="#variable-binding" aria-hidden="true" class="hash-link"><svg class="hash-link-icon" aria-hidden="true" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Variable binding</h3>
<p>Values (of any type in the type system) can be bound to variables</p>
<p><code>$var_name := "value"</code></p>
<p>The stored value can be later referenced using the expression <code>$var_name</code>.</p>
<p>The scope of a variable is limited to the 'block' in which it was bound. E.g.</p>
<pre><code class="hljs">Invoice.(
<span class="hljs-variable">$p</span> := Product.Price;
<span class="hljs-variable">$q</span> := Product.Quantity;
<span class="hljs-variable">$p</span> * <span class="hljs-variable">$q</span>
)
</code></pre>
<p>Returns Price multiplied by Quantity for the Product in the Invoice.</p>
<h2><a class="anchor" aria-hidden="true" id="functions"></a><a href="#functions" aria-hidden="true" class="hash-link"><svg class="hash-link-icon" aria-hidden="true" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Functions</h2>
<p>The function is a first-class type, and can be stored in a variable just like any other data type. A library of built-in functions is provided (link) and assigned to variables in the global scope. For example, <code>$uppercase</code> contains a function which, when invoked with a string argument, <code>str</code>, will return a string with all the characters in <code>str</code> changed to uppercase.</p>
<h3><a class="anchor" aria-hidden="true" id="invoking-a-function"></a><a href="#invoking-a-function" aria-hidden="true" class="hash-link"><svg class="hash-link-icon" aria-hidden="true" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Invoking a function</h3>
<p>A function is invoked by following its reference (or definition) by parentheses containing a comma delimited sequence of arguments.</p>
<p><strong>Examples</strong></p>
<ul>
<li><code>$uppercase("Hello")</code> returns the string "HELLO".</li>
<li><code>$substring("hello world", 0, 5)</code> returns the string "hello"</li>
<li><code>$sum([1,2,3])</code> returns the number 6</li>
</ul>
<h3><a class="anchor" aria-hidden="true" id="defining-a-function"></a><a href="#defining-a-function" aria-hidden="true" class="hash-link"><svg class="hash-link-icon" aria-hidden="true" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Defining a function</h3>
<p>Anonymous (lambda) functions can be defined using the following syntax:</p>
<p><code>function($l, $w, $h){ $l * $w * $h }</code></p>
<p>and can be invoked using</p>
<p><code>function($l, $w, $h){ $l * $w * $h }(10, 10, 5)</code> which returns 500</p>
<p>The function can also be assigned to a variable for future use (within the block)</p>
<pre><code class="hljs">(
$<span class="hljs-keyword">volume</span><span class="bash"> := <span class="hljs-keyword">function</span>(<span class="hljs-variable">$l</span>, <span class="hljs-variable">$w</span>, <span class="hljs-variable">$h</span>){ <span class="hljs-variable">$l</span> * <span class="hljs-variable">$w</span> * <span class="hljs-variable">$h</span> };</span>
$<span class="hljs-keyword">volume</span><span class="bash">(10, 10, 5);</span>
)
</code></pre>
<h3><a class="anchor" aria-hidden="true" id="function-signatures"></a><a href="#function-signatures" aria-hidden="true" class="hash-link"><svg class="hash-link-icon" aria-hidden="true" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Function signatures</h3>
<p>Functions can be defined with an optional signature which specifies the parameter types of the function. If supplied,
the evaluation engine will validate the arguments passed to the function before it is invoked. A dynamic error is
thown if the argument list does not match the signature.</p>
<p>A function signature is a string of the form <code><params:return></code>. <code>params</code> is a sequence of type symbols, each one representing an input argument's type. <code>return</code> is a single type symbol representing the return value type.</p>
<p>Type symbols work as follows:</p>
<p>Simple types:</p>
<ul>
<li><code>b</code> - Boolean</li>
<li><code>n</code> - number</li>
<li><code>s</code> - string</li>
<li><code>l</code> - <code>null</code></li>
</ul>
<p>Complex types:</p>
<ul>
<li><code>a</code> - array</li>
<li><code>o</code> - object</li>
<li><code>f</code> - function</li>
</ul>
<p>Union types:</p>
<ul>
<li><code>(sao)</code> - string, array or object</li>
<li><code>(o)</code> - same as <code>o</code></li>
<li><code>u</code> - equivalent to <code>(bnsl)</code> i.e. Boolean, number, string or <code>null</code></li>
<li><code>j</code> - any JSON type. Equivalent to <code>(bnsloa)</code> i.e. Boolean, number, string, <code>null</code>, object or array, but not function</li>
<li><code>x</code> - any type. Equivalent to <code>(bnsloaf)</code></li>
</ul>
<p>Parametrised types:</p>
<ul>
<li><code>a<s></code> - array of strings</li>
<li><code>a<x></code> - array of values of any type</li>
</ul>
<p>Some examples of signatures of built-in JSONata functions:</p>
<ul>
<li><code>$count</code> has signature <code><a:n></code>; it accepts an array and returns a number.</li>
<li><code>$append</code> has signature <code><aa:a></code>; it accepts two arrays and returns an array.</li>
<li><code>$sum</code> has signature <code><a<n>:n></code>; it accepts an array of numbers and returns a number.</li>
<li><code>$reduce</code> has signature <code><fa<j>:j></code>; it accepts a reducer function <code>f</code> and an <code>a<j></code> (array of JSON objects) and returns a JSON object.</li>
</ul>
<p>Each type symbol may also have <em>options</em> applied.</p>
<ul>
<li><code>+</code> - one or more arguments of this type
<ul>
<li>E.g. <code>$zip</code> has signature <code><a+></code>; it accepts one array, or two arrays, or three arrays, or...</li>
</ul></li>
<li><code>?</code> - optional argument
<ul>
<li>E.g. <code>$join</code> has signature <code><a<s>s?:s></code>; it accepts an array of strings and an optional joiner string which defaults to the empty string. It returns a string.</li>
</ul></li>
<li><code>-</code> - if this argument is missing, use the context value ("focus").
<ul>
<li>E.g. <code>$length</code> has signature <code><s-:n></code>; it can be called as <code>$length(OrderID)</code> (one argument) but equivalently as <code>OrderID.$length()</code>.</li>
</ul></li>
</ul>
<h3><a class="anchor" aria-hidden="true" id="recursive-functions"></a><a href="#recursive-functions" aria-hidden="true" class="hash-link"><svg class="hash-link-icon" aria-hidden="true" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Recursive functions</h3>
<p>Functions that have been assigned to variables can invoke themselves using that variable reference. This allows recursive functions to be defined. Eg.</p>
<div class="jsonata-ex">
<div>(
$factorial:= function($x){ $x <= 1 ? 1 : $x * $factorial($x-1) };
$factorial(4)
)</div>
<div>24</div>
</div>
<p>Note that it is actually possible to write a recursive function using purely anonymous functions (i.e. nothing gets assigned to variables). This is done using the <a href="https://en.wikipedia.org/wiki/Fixed-point_combinator#Fixed_point_combinators_in_lambda_calculus">Y-combinator</a> which might be an interesting <a href="#advanced-example-the-y-combinator">diversion</a> for those interested in functional programming.</p>
<h3><a class="anchor" aria-hidden="true" id="tail-call-optimization-tail-recursion"></a><a href="#tail-call-optimization-tail-recursion" aria-hidden="true" class="hash-link"><svg class="hash-link-icon" aria-hidden="true" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Tail call optimization (Tail recursion)</h3>
<p>A recursive function adds a new frame to the call stack each time it invokes itself. This can eventually lead to stack exhaustion if the function recuses beyond a certain limit. Consider the classic recursive implementation of the factorial function</p>
<pre><code class="hljs">(
$factorial := <span class="hljs-function"><span class="hljs-keyword">function</span><span class="hljs-params">($x)</span> </span>{
$x <= <span class="hljs-number">1</span> ? <span class="hljs-number">1</span> : $x * $factorial($x<span class="hljs-number">-1</span>)
};
$factorial(<span class="hljs-number">170</span>)
)
</code></pre>
<p>This function works by pushing the number onto the stack, then when the stack unwinds, multiplying it by the result of the factorial of the number minus one. Written in this way, the JSONata evaluator has no choice but to use the call stack to store the intermediate results. Given a large enough number, the call stack will overflow.</p>
<p>This is a recognised problem with functional programming and the solution is to rewrite the function slightly to avoid the <em>need</em> for the stack to store the itermediate result. The following implementation of factorial achieves this</p>
<pre><code class="hljs">(
$factorial := <span class="hljs-function"><span class="hljs-keyword">function</span><span class="hljs-params">($x)</span></span>{(
$iter := <span class="hljs-function"><span class="hljs-keyword">function</span><span class="hljs-params">($x, $acc)</span> </span>{
$x <= <span class="hljs-number">1</span> ? $acc : $iter($x - <span class="hljs-number">1</span>, $x * $acc)
};
$iter($x, <span class="hljs-number">1</span>)
)};
$factorial(<span class="hljs-number">170</span>)
)
</code></pre>
<p>Here, the multiplication is done <em>before</em> the function invokes itself and the intermediate result is carried in the second parameter <code>$acc</code> (accumulator). The invocation of itself is the <em>last</em> thing that the function does. This is known as a 'tail call', and when the JSONata parser spots this, it internally rewrites the recursion as a simple loop. Thus it can run indefinitely without growing the call stack. Functions written in this way are said to be <a href="https://en.wikipedia.org/wiki/Tail_call">tail recursive</a>.</p>
<h3><a class="anchor" aria-hidden="true" id="higher-order-functions"></a><a href="#higher-order-functions" aria-hidden="true" class="hash-link"><svg class="hash-link-icon" aria-hidden="true" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Higher order functions</h3>
<p>A function, being a first-class data type, can be passed as a parameter to another function, or returned from a function. Functions that process other functions are known as higher order functions. Consider the following example:</p>
<pre><code class="hljs">(
$twice := <span class="hljs-function"><span class="hljs-keyword">function</span><span class="hljs-params">($f)</span> </span>{ <span class="hljs-function"><span class="hljs-keyword">function</span><span class="hljs-params">($x)</span></span>{ $f($f($x)) } };
$add3 := <span class="hljs-function"><span class="hljs-keyword">function</span><span class="hljs-params">($y)</span></span>{ $y + <span class="hljs-number">3</span> };
$add6 := $twice($add3);
$add6(<span class="hljs-number">7</span>)
)
</code></pre>
<ul>
<li>The function stored in variable <code>$twice</code> is a higher order function. It takes a parameter <code>$f</code> which is a function, and returns a function which takes a parameter <code>$x</code> which, when invoked, applies the function <code>$f</code> twice to <code>$x</code>.</li>
<li><code>$add3</code> stores a function that adds 3 to its argument. Neither <code>$twice</code> or <code>$add3</code> have been invoked yet.</li>
<li><code>$twice</code> is invoked by passing the function <code>add3</code> as its argument. This returns a function that applies <code>$add3</code> twice to <em>its</em> argument. This returned function is not invoked yet, but rather assigned to the variable <code>add6</code>.</li>
<li>Finally the function in <code>$add6</code> is invoked with the argument 7, resulting in 3 being added to it twice. It returns 13.</li>
</ul>
<h3><a class="anchor" aria-hidden="true" id="functions-are-closures"></a><a href="#functions-are-closures" aria-hidden="true" class="hash-link"><svg class="hash-link-icon" aria-hidden="true" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Functions are closures</h3>
<p>When a lambda function is defined, the evaluation engine takes a snapshot of the environment and stores it with the function body definition. The environment comprises the context item (i.e. the current value in the location path) together with the current in-scope variable bindings. When the lambda function is later invoked, it is done so in that stored environment rather than the current environment at invocation time. This property is known as <em>lexical scoping</em> and is a fundamental property of <em>closures</em>.</p>
<p>Consider the following example:</p>
<pre><code class="hljs"><span class="hljs-module-access"><span class="hljs-module"><span class="hljs-identifier">Account</span>.</span>(
$AccName := <span class="hljs-keyword">function</span>() { $.'<span class="hljs-module"><span class="hljs-identifier">Account</span> </span><span class="hljs-module"><span class="hljs-identifier">Name</span>'</span> };
<span class="hljs-module"><span class="hljs-identifier">Order</span>[</span><span class="hljs-module"><span class="hljs-identifier">OrderID</span> </span>= 'order104'].<span class="hljs-module"><span class="hljs-identifier">Product</span>.</span>{
'<span class="hljs-module"><span class="hljs-identifier">Account</span>'</span>: $<span class="hljs-module"><span class="hljs-identifier">AccName</span>(</span>)</span>,
'SKU-' & <span class="hljs-constructor">$<span class="hljs-built_in">string</span>(ProductID)</span>: $.'Product Name'
}
)
</code></pre>
<p>When the function is created, the context item (referred to by '$') is the value of <code>Account</code>. Later, when the function is invoked, the context item has moved down the structure to the value of each <code>Product</code> item. However, the function body is invoked in the environment that was stored when it was defined, so its context item is the value of <code>Account</code>. This is a somewhat contrived example, you wouldn't really need a function to do this. The expression produces the following result:</p>
<pre><code class="hljs">{
<span class="hljs-attr">"Account"</span>: <span class="hljs-string">"Firefly"</span>,
<span class="hljs-attr">"SKU-858383"</span>: <span class="hljs-string">"Bowler Hat"</span>,
<span class="hljs-attr">"SKU-345664"</span>: <span class="hljs-string">"Cloak"</span>
}
</code></pre>
<h3><a class="anchor" aria-hidden="true" id="partial-function-application"></a><a href="#partial-function-application" aria-hidden="true" class="hash-link"><svg class="hash-link-icon" aria-hidden="true" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Partial function application</h3>
<p>Functions can <a href="https://en.wikipedia.org/wiki/Partial_application">partially applied</a> by invoking the function with one or more (but not all)
arguments replaced by a question mark <code>?</code> placeholder. The result of this is another function whose arity (number of parameters) is reduced
by the number of arguments supplied to the original function. This returned function can be treated like any other newly defined function,
e.g. bound to a variable, passed to a higher-order function, etc.</p>
<p><strong>Examples</strong></p>
<ul>
<li><p>Create a function to return the first five characters of a string by partially applying the <code>$substring</code> function</p>
<div class="jsonata-ex">
<div>(
$first5 := $substring(?, 0, 5);
$first5("Hello, World")
)</div>
<div>"Hello"</div>
</div>
</li>
<li><p>Partially applied function can be further partially applied</p>
<div class="jsonata-ex">
<div>(
$firstN := $substring(?, 0, ?);
$first5 := $firstN(?, 5);
$first5("Hello, World")
)</div>
<div>"Hello"</div>
</div>
</li>
</ul>
<h3><a class="anchor" aria-hidden="true" id="function-chaining"></a><a href="#function-chaining" aria-hidden="true" class="hash-link"><svg class="hash-link-icon" aria-hidden="true" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Function chaining</h3>
<p>Function chaining can be used in two ways:</p>
<ol>
<li><p>To avoid lots of nesting when multiple functions are applied to a value</p></li>
<li><p>As a higher-order construct for defining new functions by combining existing functions</p></li>
</ol>
<h4><a class="anchor" aria-hidden="true" id="invocation-chaining"></a><a href="#invocation-chaining" aria-hidden="true" class="hash-link"><svg class="hash-link-icon" aria-hidden="true" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Invocation chaining</h4>
<p><code>value ~> $funcA ~> $funcB</code><br>
is equivalent to<br>
<code>$funcB($funcA(value))</code></p>
<p><strong>Examples</strong></p>
<ul>
<li><code>Customer.Email ~> $substringAfter("@") ~> $substringBefore(".") ~> $uppercase()</code></li>
</ul>
<h4><a class="anchor" aria-hidden="true" id="function-composition"></a><a href="#function-composition" aria-hidden="true" class="hash-link"><svg class="hash-link-icon" aria-hidden="true" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Function composition</h4>
<p><a href="https://en.wikipedia.org/wiki/Function_composition">Function composition</a> is the application of one function to another function
to produce a third function.</p>
<p><code>$funcC := $funcA ~> $funcB</code><br>
is equivalent to<br>
<code>$funcC := function($arg) { $funcB($funcA($arg)) }</code></p>
<p><strong>Examples</strong></p>
<ul>
<li>Create a new function by chaining two existing functions
<div class="jsonata-ex">
<div>(
$normalize := $uppercase ~> $trim;
$normalize(" Some Words ")
)</div>
<div>"SOME WORDS"</div>
</div>
</li>
</ul>
<h3><a class="anchor" aria-hidden="true" id="functions-as-first-class-values"></a><a href="#functions-as-first-class-values" aria-hidden="true" class="hash-link"><svg class="hash-link-icon" aria-hidden="true" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Functions as first class values</h3>
<p>Function composition can be combined with partial function application to produce a very compact syntax for defining new
functions.</p>
<p><strong>Examples</strong></p>
<ul>
<li>Create a new function by chaining two partially evaluated functions
<div class="jsonata-ex">
<div>(
$first5Capitalized := $substring(?, 0, 5) ~> $uppercase(?);
$first5Capitalized(Address.City)
)</div>
<div>"WINCH"</div>
</div>
</li>
</ul>
<h3><a class="anchor" aria-hidden="true" id="advanced-example---the-y-combinator"></a><a href="#advanced-example---the-y-combinator" aria-hidden="true" class="hash-link"><svg class="hash-link-icon" aria-hidden="true" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Advanced example - The Y-combinator</h3>
<p>There is no need to read this section - it will do nothing for your sanity or ability to manipulate JSON data.</p>
<p>Earlier we learned how to write a recursive function to calculate the factorial of a number and hinted that this could be done without naming any functions. We can take higher-order functions to the extreme and write the following:</p>
<p><code>λ($f) { λ($x) { $x($x) }( λ($g) { $f( (λ($a) {$g($g)($a)}))})}(λ($f) { λ($n) { $n < 2 ? 1 : $n * $f($n - 1) } })(6)</code></p>
<p>which produces the result <code>720</code>. The Greek lambda (λ) symbol can be used in place of the word <code>function</code> which, if you can find it on your keyboard, will save screen space and please the fans of <a href="https://en.wikipedia.org/wiki/Lambda_calculus">lambda calculus</a>.</p>
<p>The first part of this above expression is an implementation of the <a href="https://en.wikipedia.org/wiki/Fixed-point_combinator#Fixed_point_combinators_in_lambda_calculus">Y-combinator</a> in this language. We could assign it to a variable and apply it to other recursive anonymous functions:</p>
<pre><code class="hljs">(
$Y := λ(<span class="hljs-name">$f</span>) { λ(<span class="hljs-name">$x</span>) { $x(<span class="hljs-name">$x</span>) }( λ(<span class="hljs-name">$g</span>) { $f( (<span class="hljs-name">λ</span>(<span class="hljs-name">$a</span>) {$g(<span class="hljs-name">$g</span>)(<span class="hljs-name">$a</span>)}))})}<span class="hljs-comment">;</span>
[<span class="hljs-name">1</span>,<span class="hljs-number">2</span>,<span class="hljs-number">3</span>,<span class="hljs-number">4</span>,<span class="hljs-number">5</span>,<span class="hljs-number">6</span>,<span class="hljs-number">7</span>,<span class="hljs-number">8</span>,<span class="hljs-number">9</span>] . $Y(<span class="hljs-name">λ</span>(<span class="hljs-name">$f</span>) { λ(<span class="hljs-name">$n</span>) { $n <= <span class="hljs-number">1</span> ? $n : $f(<span class="hljs-name">$n-1</span>) + $f(<span class="hljs-name">$n-2</span>) } }) (<span class="hljs-name">$</span>)
)
</code></pre>
<p>to produce the Fibonacci series <code>[ 1, 1, 2, 3, 5, 8, 13, 21, 34 ]</code>.</p>
<p>But we don't need to do any of this. Far more sensible to use named functions:</p>
<pre><code class="hljs">(
$fib := λ($n) { $n <= <span class="hljs-number">1</span> ? $n : $fib($n<span class="hljs-number">-1</span>) + $fib($n<span class="hljs-number">-2</span>) };
[<span class="hljs-number">1</span>,<span class="hljs-number">2</span>,<span class="hljs-number">3</span>,<span class="hljs-number">4</span>,<span class="hljs-number">5</span>,<span class="hljs-number">6</span>,<span class="hljs-number">7</span>,<span class="hljs-number">8</span>,<span class="hljs-number">9</span>] . $fib($)
)
</code></pre>
</span></div></article></div><div class="docs-prevnext"><a class="docs-prev button" href="/processing"><span class="arrow-prev">← </span><span>Processing Model</span></a><a class="docs-next button" href="/regex"><span>Regular Expressions</span><span class="arrow-next"> →</span></a></div></div></div><nav class="onPageNav"><ul class="toc-headings"><li><a href="#comments">Comments</a></li><li><a href="#conditional-logic">Conditional logic</a></li><li><a href="#variables">Variables</a><ul class="toc-headings"><li><a href="#built-in-variables">Built-in variables</a></li><li><a href="#variable-binding">Variable binding</a></li></ul></li><li><a href="#functions">Functions</a><ul class="toc-headings"><li><a href="#invoking-a-function">Invoking a function</a></li><li><a href="#defining-a-function">Defining a function</a></li><li><a href="#function-signatures">Function signatures</a></li><li><a href="#recursive-functions">Recursive functions</a></li><li><a href="#tail-call-optimization-tail-recursion">Tail call optimization (Tail recursion)</a></li><li><a href="#higher-order-functions">Higher order functions</a></li><li><a href="#functions-are-closures">Functions are closures</a></li><li><a href="#partial-function-application">Partial function application</a></li><li><a href="#function-chaining">Function chaining</a></li><li><a href="#functions-as-first-class-values">Functions as first class values</a></li><li><a href="#advanced-example---the-y-combinator">Advanced example - The Y-combinator</a></li></ul></li></ul></nav></div><footer class="nav-footer" id="footer"><section class="sitemap"><a href="/" class="nav-home"><img src="/img/jsonata-white-167.png" alt="JSONata"/></a><div><h5>JSONata</h5><a href="http://jsonata.org" target="_blank" rel="noreferrer noopener">JSON query and<br/>transformation language</a><a href="http://try.jsonata.org" target="_blank" rel="noreferrer noopener">Go play in the<br/>JSONata Exerciser</a></div><div><h5>Community</h5><a href="https://stackoverflow.com/questions/tagged/jsonata" target="_blank" rel="noreferrer noopener">Stack Overflow</a><a href="https://jsonata.slack.com/">Project Chat</a><a href="https://twitter.com/" target="_blank" rel="noreferrer noopener">Twitter</a></div><div><h5>More</h5><a href="https://github.com/jsonata-js/jsonata">GitHub</a><a class="github-button" href="https://github.com/jsonata-js/jsonata" data-icon="octicon-star" data-count-href="/jsonata-js/jsonata/stargazers" data-show-count="true" data-count-aria-label="# stargazers on GitHub" aria-label="Star this project on GitHub">Star</a></div></section><section class="copyright">Copyright © 2021 JSONata.org</section></footer></div></body></html>