-
Notifications
You must be signed in to change notification settings - Fork 7
/
quick-help.html
2053 lines (1305 loc) · 95.9 KB
/
quick-help.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
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<?xml version="1.0" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title></title>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<link rev="made" href="mailto:[email protected]" />
</head>
<body>
<ul id="index">
<li><a href="#Links-Syntax">Links Syntax</a>
<ul>
<li><a href="#Comments">Comments</a></li>
<li><a href="#Literals">Literals</a></li>
<li><a href="#Arithmetic">Arithmetic</a></li>
<li><a href="#Lists">Lists</a></li>
<li><a href="#Pattern-matching-on-lists">Pattern matching on lists</a></li>
<li><a href="#Integer-Ranges">Integer Ranges</a></li>
<li><a href="#Pairs-Tuples-and-Records">Pairs, Tuples, and Records</a>
<ul>
<li><a href="#Record-modifications">Record modifications</a></li>
</ul>
</li>
<li><a href="#Polymorphic-variants">Polymorphic variants</a></li>
<li><a href="#XML-Quasiquotes">XML Quasiquotes</a></li>
<li><a href="#Forms">Forms</a></li>
<li><a href="#Comparisons-and-Boolean-Expressions">Comparisons and Boolean Expressions</a></li>
<li><a href="#Conditionals">Conditionals</a></li>
<li><a href="#Variables">Variables</a></li>
<li><a href="#Blocks">Blocks</a></li>
<li><a href="#Functions">Functions</a></li>
<li><a href="#Loops-List-Comprehensions">Loops (List Comprehensions)</a>
<ul>
<li><a href="#Filtering-comprehensions">Filtering comprehensions</a></li>
<li><a href="#Sorting-comprehensions">Sorting comprehensions</a></li>
<li><a href="#Multi-generator-comprehensions">Multi-generator comprehensions</a></li>
</ul>
</li>
<li><a href="#Database-access">Database access</a>
<ul>
<li><a href="#Using-tables">Using tables</a></li>
<li><a href="#Database-modifications">Database modifications</a></li>
<li><a href="#Table-constraints">Table constraints</a></li>
<li><a href="#Database-abstraction">Database abstraction</a></li>
<li><a href="#Query-blocks">Query blocks</a></li>
</ul>
</li>
<li><a href="#Structural-pattern-matching">Structural pattern matching</a></li>
<li><a href="#Regular-expressions">Regular expressions</a>
<ul>
<li><a href="#Special-feature:-regexes-and-the-database">Special feature: regexes and the database</a></li>
<li><a href="#Limitations">Limitations</a></li>
</ul>
</li>
</ul>
</li>
<li><a href="#Typing">Typing</a>
<ul>
<li><a href="#Types-in-Links">Types in Links</a></li>
<li><a href="#Base-types">Base types</a></li>
<li><a href="#Type-annotations">Type annotations</a></li>
<li><a href="#Type-aliases">Type aliases</a></li>
<li><a href="#Type-variables">Type variables</a></li>
<li><a href="#Function-types-and-effects">Function types and effects</a></li>
<li><a href="#Kinds-and-subkinding">Kinds and subkinding</a></li>
</ul>
</li>
<li><a href="#Features">Features</a>
<ul>
<li><a href="#Formlets">Formlets</a></li>
<li><a href="#Concurrency">Concurrency</a></li>
<li><a href="#Located-code-and-remote-procedure-calls">Located code and remote procedure calls</a></li>
<li><a href="#Handling-User-Actions">Handling User Actions</a>
<ul>
<li><a href="#Interpreting-the-Event">Interpreting the Event</a></li>
</ul>
</li>
<li><a href="#Modifying-the-Web-Page">Modifying the Web Page</a>
<ul>
<li><a href="#DOM-operations">DOM operations</a></li>
</ul>
</li>
<li><a href="#XML-operations">XML operations</a></li>
<li><a href="#Cookies">Cookies</a></li>
</ul>
</li>
<li><a href="#Library-functions">Library functions</a>
<ul>
<li><a href="#Explicit-type-conversions">Explicit type conversions</a></li>
<li><a href="#Negation">Negation</a></li>
<li><a href="#Character-classification">Character classification</a></li>
<li><a href="#Case-conversion">Case conversion</a></li>
<li><a href="#Floating-point-functions">Floating point functions</a></li>
<li><a href="#Miscellaneous">Miscellaneous</a></li>
</ul>
</li>
<li><a href="#Standard-library-prelude">Standard library (prelude)</a>
<ul>
<li><a href="#List-utilities">List utilities</a></li>
<li><a href="#Web-related-features">Web-related features</a></li>
<li><a href="#Formlet-library">Formlet library</a></li>
</ul>
</li>
<li><a href="#Running-links">Running links</a>
<ul>
<li><a href="#The-interactive-shell">The interactive shell</a>
<ul>
<li><a href="#Directives">Directives</a></li>
</ul>
</li>
<li><a href="#Configuration-settings">Configuration settings</a></li>
</ul>
</li>
</ul>
<h1 id="Links-Syntax">Links Syntax</h1>
<h2 id="Comments">Comments</h2>
<p>Comments are introduced by a hash mark, <code>#</code>, and continue for the rest of the line.</p>
<h2 id="Literals">Literals</h2>
<ul>
<li><p>Integers: <code>2</code>, <code>7</code></p>
</li>
<li><p>Floating point numbers: <code>3.</code>, <code>14.5</code>,</p>
</li>
<li><p>Booleans: <code>true</code>, <code>false</code>.</p>
</li>
<li><p>Strings: <code>"Cappuccino"</code>, <code>"\"I've dropped the toothpaste,\" Tom said, crestfallen."</code>.</p>
</li>
<li><p>Characters: <code>'a'</code>, <code>'9'</code>, <code>'\012'</code>.</p>
</li>
</ul>
<h2 id="Arithmetic">Arithmetic</h2>
<p>Links supports the standard arithmetic operators.</p>
<pre><code> + : (Int, Int) -> Int
- : (Int, Int) -> Int
* : (Int, Int) -> Int
/ : (Int, Int) -> Int
^ : (Int, Int) -> Int
mod : (Int, Int) -> Int
*. : (Float, Float) -> Float
+. : (Float, Float) -> Float
-. : (Float, Float) -> Float
/. : (Float, Float) -> Float
^. : (Float, Float) -> Float</code></pre>
<p>As Links does not yet have any support for overloading, the floating point versions are distinguished using the "." suffix. The arithmetic operators can be used infix as is or prefix when enclosed in parentheses.</p>
<pre><code> 1+2*3</code></pre>
<p>returns <code>7</code>.</p>
<pre><code> (*.)(6.0, 7.)</code></pre>
<p>returns <code>42.</code>.</p>
<h2 id="Lists">Lists</h2>
<p>A list is a finite sequence of values, constructed using <code>[]</code> (pronounced "nil") and <code>::</code> (pronounced "cons").</p>
<pre><code> 1 :: 4 :: 9 :: 16 :: []</code></pre>
<p>A list can be created directly by wrapping a series of comma-separated expressions between brackets:</p>
<pre><code> [1, 4, 9, 16]
["apple", "banana", "pear"]
[]
x = true;
[true, false, x, true]</code></pre>
<p>Note that all elements of a list must be of the same type.</p>
<p>Lists support the "concatenate" operation, denoted by two plus characters:</p>
<pre><code> [1, 2] ++ [3, 4, 5] == [1, 2, 3, 4, 5]</code></pre>
<p>And they're comparable, with <code>==</code>, as you can see!</p>
<p>The ``Cons'' operator (<code>::</code>) appends an element to the start of a list.</p>
<pre><code> links> 1::[2,3,4,5];
[1, 2, 3, 4, 5] : [Int]</code></pre>
<p>The head (<code>hd</code>) and tail (<code>tl</code>) functions each take a single list as an argument. They return respectively: the first element of the list; and the list consisting of all elements but the first from the original list.</p>
<pre><code> links> hd([1,2,3]);
1 : Int
links> tl([1,2,3]);
[2, 3] : [Int]</code></pre>
<p>The take and drop functions return respectively: the first n elements of a list; and all but the first n elements of a list.</p>
<pre><code> links> take(2,[1,2,3]);
[1, 2] : [Int]
links> drop(2,[1,2,3]);
[3] : [Int]</code></pre>
<h2 id="Pattern-matching-on-lists">Pattern matching on lists</h2>
<p>Cons and nil can also be used in patterns, to deconstruct lists:</p>
<pre><code> switch (s) {
case [] -> Empty
case x::xs -> NonEmpty
}</code></pre>
<h2 id="Integer-Ranges">Integer Ranges</h2>
<p>The syntax <code>[a .. b]</code> constructs a list of all the integers between <code>a</code> and <code>b</code>, inclusive. The result is empty if <code>a</code> is greater than <code>b</code>.</p>
<h2 id="Pairs-Tuples-and-Records">Pairs, Tuples, and Records</h2>
<p>A tuple is a finite sequence of values, possibly of different types. An <i>n</i>-tuple is constructed by enclosing <i>n</i> expressions in parenthesis and separating them with commas:</p>
<pre><code> (a, "OK")
(true, "a string", 42)</code></pre>
<p>A record is something like a tuple, but its fields are indexed by field names rather than integer indices. A record is written like a tuple but with fieldnames preceeding the fields:</p>
<pre><code> (lastname="Bond", firstname="James", license="To kill")</code></pre>
<p>Field names are not enclosed in quotes and are not expressions. They are not evaluated. Note that, whereas the content of a field can be any expression, the field name must be literally present when constructing a record. For example:</p>
<pre><code> var item = (drinkname = "latte", price = 2.0 +. 0.5) # OK
var item = ("drink" + "name" = "latte", price = 2.0 +. 0.5) # NOT OK</code></pre>
<p>You can access the fields of a record by <i>projecting</i> them, using the dot notation:</p>
<pre><code> item.drinkname == "latte"
(lastname="Bond", firstname="James").lastname == "Bond"</code></pre>
<h3 id="Record-modifications">Record modifications</h3>
<p>You can <i>add</i> a field to an arbitrary record using the <i>record extension</i> operation. This operation works only when the field is not already present in the record. As an example:</p>
<pre><code> (caffeineContent = 60 | item)</code></pre>
<p>Given the definition from above, this would yield a value</p>
<pre><code> (caffeineContent = 60, drinkname = "latte", price = 2.5)</code></pre>
<p>To <i>overwrite</i> the value in a field, when that field is already present, use the "with" notation:</p>
<pre><code> (item with drinkname = "capuccino")</code></pre>
<p>This yields</p>
<pre><code> (drinkname="capuccino", price=2.5)</code></pre>
<p>Records do not need to be declared; a given field name can appear in any record. The only requirement is that a given field is used with a consistent type, insofar as the the values may interact. It is acceptable to use a particular field name with different types, as long as the two are used separately--that is, as long as the same value will never be used in differently-typed expressions.</p>
<h2 id="Polymorphic-variants">Polymorphic variants</h2>
<p>A "variant type" is one that uses explicit "tags" (or "labels") to distinguish different sets of possible values as to their meaning. For example, a mode of transport may be either Automobile or Camel. If it is Automobile, we want to know what fuel it takes; if it is Camel, we want to know how many humps it has. In Links, values like these can be expressed as follows:</p>
<pre><code> Automobile(Diesel)
Automobile(Unleaded)
Camel(2)</code></pre>
<p>The <i>type</i> that includes such values is written as follows:</p>
<pre><code> [|Automobile: [|Diesel:() | Unleaded:() | Biodiesel:()|] |
Camel: Int |]</code></pre>
<p>The boxy brackets <code>[| |]</code> delimit a variant type, and variant labels are separated by a pipe <code>|</code>. After each variant label, separated by a colon <code>:</code>, is the type of its contents--a Camel has a number of humps so its content type is <code>Int</code>, whereas the Automobile content type is another variant type, <code>[|Diesel | Unleaded|]</code>.</p>
<p>In Links, <i>a variant tag always begins with a capital letter</i>. Any string beginning with a capital letter, used in a value context, denotes a variant label.</p>
<p>To inspect a variant value, use <i>pattern matching</i>. Pattern matching is accomplished using the <code>switch</code> form, which has a target expression and a case for each variant label. The following expression determines the effective number of humps of a transport (autos have no humps):</p>
<pre><code> switch (target) {
case Automobile(fuelType) -> 0
case Camel(humpCount) -> humpCount
}</code></pre>
<p>The expression <code>expr</code> is evaluated to produce a value of variant type; then the label is examined and one of the cases is chosen. The lowercase word following the variant label in a case is bound to the content of the target value (provided that case actually matches the target). This allows us to use the variable <code>humpCount</code> within the body of the <code>Camel</code> case. The body of a case (everything between the <code>-></code> and the next case (if any) or the end of the switch) produces the result of the whole switch expression, and all case bodies of a switch must have the same type.</p>
<p>Type-checking will also ensure that all possible cases are matched by the <code>switch</code> expression. To handle arbitrary variant values, you can add an open case to the end of the switch:</p>
<pre><code> switch (target) {
case Automobile(fuelType) -> 0
case Camel(humpCount) -> humpCount
case other -> 0
}</code></pre>
<p>Since <code>other</code> begins with a lowercase letter, it is a variable, which matches any value. Unlike the variables in the previous cases, which are wrapped inside variant labels, <code>other</code> is used here as the complete pattern to match for its case, so it will match anything. Patterns are tried in the order they are given, so the <code>other</code> case will not by selected unless the previous cases do not match.</p>
<p>Here we assume that nothing other than a camel has humps.</p>
<h2 id="XML-Quasiquotes">XML Quasiquotes</h2>
<p>Also called "quasis," these are the principal way to embed XML values within your program. A quasi is introduced by an XML start-tag such as <code><foo></code>. Inside a quasi, you may escape from the XML mode back into Links syntax, by enclosing the Links code within braces { }. When the quasi is evaluated, all its escaped expressions will be evaluated, and their values will be embedded within the constructed XML value. For example:</p>
<pre><code> <html>
<ul>
<li> First item: {item1} </li>
<li> Second item: {item2} </li>
</ul>
</html></code></pre>
<p>Within an XML quasi, a variety of special features can be used to handle browser events. See <a href="#Handling-User-Actions">"Handling User Actions"</a>, below, for more information on these features.</p>
<p>To introduce a <i>forest</i> of XML nodes that have no mutually enclosing XML element, use the special <code><#>...</#></code> syntax:</p>
<pre><code> <#>
Name: <b>{name}</b>
</#></code></pre>
<p>Here, a <i>sequence</i> of nodes (first, an XML text node, and then a <b> element) becomes as a single expression. This value can be included directly in other XML quasis:</p>
<pre><code> var nameLine = <#> Name: <b>{name}</b> </#>;
<div>
{nameLine} <br />
The Links Team
</div></code></pre>
<h2 id="Forms">Forms</h2>
<p>Links provides two special attributes for programming with HTML forms: <code>l:name</code>, which binds the value of an input field to a variable, and <code>l:onsubmit</code>, with which you can supply an expression to be evaluated when the form is submitted.</p>
<pre><code> <form l:onsubmit="{say_hello(personName)}">
What is your name?
<input l:name="{personName}"/>
</form></code></pre>
<p>The <code>personName</code> variable bound by the <code>l:name</code> attribute is in scope in the <code>l:onsubmit</code> expression, which may also contain references to other variables in the enclosing scope. The values of these variables are passed from form to form automatically.</p>
<p>Unfortunately, the <code>l:</code> mechanism does not support any abstraction in building forms. For a more abstraction-friendly construct, see <a href="#Formlets">"Formlets"</a>, describing a mechanism for abstracting form fragments.</p>
<h2 id="Comparisons-and-Boolean-Expressions">Comparisons and Boolean Expressions</h2>
<p>Comparisons are binary operations that yield a true/false value.</p>
<ul>
<li><p>==</p>
<p>True iff the operands evaluate to the same value.</p>
</li>
<li><p><></p>
<p>True iff the operands evaluate to different values.</p>
</li>
<li><p><</p>
<p>True iff the left operand's value is less than the right operand's</p>
</li>
<li><p>></p>
<p>True iff the right operand's value is less than the left operand's</p>
</li>
<li><p><=</p>
<p>True iff the left operand's value is less than or equal to the right operand's</p>
</li>
<li><p>>=</p>
<p>True iff the right operand's value is less than or equal to the left operand's</p>
</li>
</ul>
<p>Boolean expressions can be combined using the boolean operators:</p>
<ul>
<li><p>&&</p>
</li>
<li><p>||</p>
</li>
<li><p>not</p>
</li>
</ul>
<h2 id="Conditionals">Conditionals</h2>
<p>A conditional expression has a condition, a consequent, and an else clause. None of the three may be omitted.</p>
<pre><code> if (x == y)
expr1
else
expr2</code></pre>
<p>Curly braces can be wrapped around either clause, no matter how many sub-expressions they contain, and <i>must</i> be so wrapped if you want the clause to consist of more than one semicolon-separated expression.</p>
<p>Note that an <code>if</code>-<code>else</code> expression <i>always</i> returns a value in Links; the return values of the two branches must be of the same type, and both branches are required.</p>
<h2 id="Variables">Variables</h2>
<p>Variables are single-assignment in Links. The form</p>
<pre><code> var x = expr;
etc</code></pre>
<p>evaluates <code>expr</code> and binds the name <code>x</code> to the resulting value, within the expression <code>etc</code>.</p>
<p>Variable assignments have block scope. The following example</p>
<pre><code> var x = 1;
if (condition) {
var x = 2
} else {
var x = 3
};
print int_to_string(x);</code></pre>
<p>prints <code>1</code> because the assignments to <code>x</code> within the if clauses only bind within those clauses. If you want the value printed to depend on the condition, you should assign to <code>x</code> from the result of the whole <code>if</code> expression:</p>
<pre><code> var x = if (condition) {
2
} else {
3
};
print int_to_string(x);</code></pre>
<h2 id="Blocks">Blocks</h2>
<p>A sequence of variable bindings separated by semicolons is evaluated in text order, binding each value to the corresponding name in what follows. Variables cannot be rebound; later bindings of the same name shadow preceding ones:</p>
<pre><code> var x = 1;
var y = 2;
var x = 2;
var z = x + y; # z is now bound to 4</code></pre>
<p>The scope of a binding is strictly within its immediate block. As a result, the following code may not do what you expect:</p>
<pre><code> var x = 0;
if (a == b)
var x = 1;
else
var x = 2;
alert(x);</code></pre>
<p>The value printed by <code>alert</code> will be 0. That's because the other two bindings only bind x within the corresponding clauses of the conditional. This may come as a surprise to programmers used to imperative languages.</p>
<h2 id="Functions">Functions</h2>
<p>Functions can be named or anonymous. Named functions look like this:</p>
<pre><code> fun foo(x, y, z)
{
# ... body
}</code></pre>
<p>Anonymous functions just omit the name: <code>fun (x) { x + 1 }</code> is an expression that evaluates to an anonymous function value.</p>
<p>Function values, whether named or anonymous, are lexical closures; any variables free in the body must refer to bindings from a surrounding lexical scope. The smallest surrounding scope is chosen.</p>
<p>A function can be called by using its name, followed by a list of arguments in parentheses:</p>
<pre><code> foo(1, 2, 7)</code></pre>
<p>This works whether <code>foo</code> is a function defined with a name, as <code>fun foo(...) {...}</code>, or a variable bound to a functional value, as</p>
<pre><code> var inc = fun (x) {x + 1};
inc(7)</code></pre>
<p>This block returns <code>8</code>.</p>
<p>Any expression that evaluates to a function value can be called:</p>
<pre><code> (if (true) fun (x) { x + 1 }
else fun (x) { x + 2 })(3)</code></pre>
<h2 id="Loops-List-Comprehensions">Loops (List Comprehensions)</h2>
<p>The principal loop construct in Links is the list comprehension:</p>
<pre><code> for (x <- source)
body</code></pre>
<p>Both the source and the body should be expressions that evaluate to lists.</p>
<p>The value of a comprehension is the concatenation of all the lists produced by evaluating the body, once for each element of <i>source</i>, and binding that element to the variable <code>x</code>. For example:</p>
<pre><code> var source_list = [1, 2, 3];
for (x <- source_list)
[ x*x ]</code></pre>
<p>constructs a list of the squares of the values in <code>source_list</code>. Note that more than one value can be included in the body list:</p>
<pre><code> var source_list = [2, 3, 7, 8, 9, 55];
for (n <- source_list)
if (odd(n))
[n, n+1]
else
[n]</code></pre>
<p>This example returns <code>[2, 3, 4, 7, 8, 8, 9, 10, 55, 56]</code>.</p>
<p>Other forms of looping can be implemented using tail recursion.</p>
<h3 id="Filtering-comprehensions">Filtering comprehensions</h3>
<p>A comprehension can be filtered using the <code>where</code> clause.</p>
<pre><code> var source = [2, 3, 4, 5, 6, 7];
for (x <- source)
where (odd(x))
[x+1]</code></pre>
<p>returns <code>[4, 6, 8]</code>.</p>
<p>A <code>where</code> clause is equivalent to a condition nested within a comprehension:</p>
<pre><code> for (x <- src)
where (pred)
expr</code></pre>
<p>is equivalent to</p>
<pre><code> for (x <- src)
if (pred)
expr
else []</code></pre>
<p><code>where</code> is a clause on <code>for</code> comprehensions: it cannot be used outside of a <code>for</code>.</p>
<h3 id="Sorting-comprehensions">Sorting comprehensions</h3>
<p>The <code>orderby</code> clause on <code>for</code> comprehensions is used to sort the source before evaluating the body.</p>
<p>For example, suppose "models" is a list declared previously with type <code>[(release_year:Int,model_number:Int,model_name:String)]</code>, describing models of an automobile make. Then the following will return a list of pairs describing the models, ordered by their year of release:</p>
<pre><code> for (m <- models)
orderby (m.release_year)
[(m.model_number, m.model_name)]</code></pre>
<h3 id="Multi-generator-comprehensions">Multi-generator comprehensions</h3>
<p>A comprehension can draw elements from more than one list. For each element produced by the first <i>generator</i>, Links iterates over all the items produced by the remaining generators.</p>
<p>For example:</p>
<pre><code> links>
for (fruit <- ["apple", "orange", "banana"], i <- [1..4])
[(i, fruit)];
[(1, "apple"), (2, "apple"), (3, "apple"), (4, "apple"),
(1, "banana"), (2, "banana"), (3, "banana"), (4, "banana"),
(1, "orange"), (2, "orange"), (3, "orange"), (4, "orange")] : [(Int, String)]</code></pre>
<p>You can also impose an order on all the elements produced by the series of generators in a comprehension header, as in:</p>
<pre><code> links>
for (fruit <- ["apple", "orange", "banana"], i <- [1..4])
orderby (fruit)
[(i, fruit)];
[(1, "apple"), (2, "apple"), (3, "apple"), (4, "apple"),
(1, "banana"), (2, "banana"), (3, "banana"), (4, "banana"),
(1, "orange"), (2, "orange"), (3, "orange"), (4, "orange")] : [(Int, String)]</code></pre>
<p>Links will produce a list of tuple elements as dictated by the generators, then sort them, and finally evaluate the body expression for each element produced. Note that it is the source elements, <i>not</i> the body elements, which are sorted.</p>
<p>The effect of multi-generator comprehensions is much like that of nested comprehensions: the comprehension</p>
<pre><code> for (fruit <- ["apple", "orange", "banana"], i <- [1..4])
[(i, fruit)];</code></pre>
<p>behaves just like this one:</p>
<pre><code> for (fruit <- ["apple", "orange", "banana"])
for (i <- [1..4])
[(i, fruit)];</code></pre>
<p>But multi-generator comprehensions are different from the nested counterparts when it comes to clauses such as <code>orderby</code>. This is because the <code>orderby</code> clause sorts the list of tuples produced by all the generators in the <i>most recent</i> comprehension header. When using nested single-generator comprehesions, you are sorting one series of elements which is then collected by another comprehension, for a result than may not obey the desired ordering. For example,</p>
<pre><code> links> for (fruit <- ["apple", "orange", "banana"])
for (i <- [1..4])
orderby (i)
[(i, fruit)];
[(1, "apple"), (2, "apple"), (3, "apple"), (4, "apple"),
(1, "banana"), (2, "banana"), (3, "banana"), (4, "banana"),
(1, "orange"), (2, "orange"), (3, "orange"), (4, "orange")] : [(Int, String)]</code></pre>
<h2 id="Database-access">Database access</h2>
<p>To access the database, use <i>database</i> and <i>table expressions</i>, which produce first-class values representing, respectively, database connections and tables within such connected databases.</p>
<p>To connect to a given database instance using a particular database driver, use a <code>database</code> expression.</p>
<pre><code> database <database-name> <driver-name> <parameter-string>;</code></pre>
<p>The <code><parameter string></code> is a colon-separated string whose interpretation is driver-dependent, but which usually includes the hostname, port, username and password. For example, to connect to the database <code>ice_cream</code> using the <code>mysql</code> driver, using the default host name and the port 3306, and bind the resulting connection to the variable <code>db</code>, use</p>
<pre><code> var db = database "ice_cream" "mysql" ":3306:web:";</code></pre>
<p>The driver and parameter string default to the configuration values <code>database_driver</code> and <code>database_args</code>, so at a minimum you need only give the instance name:</p>
<pre><code> var db = database "ice_cream";</code></pre>
<p>Supported drivers include <code>postgres</code>, <code>mysql</code> and <code>sqlite</code>. The <code><parameter-string></code> field is presently only used by the postgres and mysql drivers and has the form:</p>
<pre><code> host:port:user:password</code></pre>
<p>When a database expression is evaluated on the server a connection is automatically opened if one is not already open.</p>
<p>Table-handles are created using <code>table</code> expressions, which need the table's name, its type, as a record, and the database connection (a value produced by a <code>database</code> expression as above):</p>
<pre><code> table <table-name> with <row-type> from <database-connection>;</code></pre>
<p>For example, to create a handle to the table <code>ice_cream</code> with fields <code>i</code> and <code>f</code> both of type <code>Int</code> associated with the database <code>db</code>, and bind it to the variable <code>fac_table</code>, use:</p>
<pre><code> var parlors = table "ice_cream_parlors"
with (name : String, fans : Int) from db;</code></pre>
<p>The variable <code>parlors</code> then has type <code>TableHandle((name : String, fans : Int), (name : String, fans : Int), (name : String, fans : Int))</code>. The three arguments to the <code>TableHandle</code> type constructor together identify the type of a row and its constraints (See <a href="#Table-constraints">"Table constraints"</a>).</p>
<h3 id="Using-tables">Using tables</h3>
<p>To iterate over the items of a table--or just to fetch one row--use <code>for</code> comprehensions.</p>
<p>Since a table-handle in Links is different from a list, we cannot simply draw elements directly from a table as we draw them from a list. But a special form of generator accepts a table-handle as its source:</p>
<pre><code> var parlors = table "ice_cream_parlors"
with (name : String, fans : Int) from db;
for (p <-- parlors)
where (p.flavors > 1)
[x]</code></pre>
<p>This comprehension selects all the elements from the <code>ice_cream_parlors</code> table that serve more than one flavor.</p>
<p>The special <i>long-arrow generator</i> <code><--</code> accepts a table-handle, and not a list, as its right-hand side.</p>
<p>The long-arrow generator also specifies that the comprehension in which it participates <i>must</i> be executed by a single SQL query at run time. When an expression is executed as a query, it should be relatively efficient because, for example, any comprehension filtering should be performed by the database, before involving the Links runtime system. The database system may be able to do this efficiently by using its indexes.</p>
<p>When you don't want to specify that an expression becomes a query, you can extract all the rows of a table directly using the special function <code>asList</code>. The <code>asList</code> function takes a single argument, a table handle, and produces a list of all the rows in the table at the time when the function is applied.</p>
<p>For example, you may write</p>
<pre><code> for (p <-- parlors)
where (p.flavors <= 20)
[(name = p.name)]</code></pre>
<p>to extract from the <code>parlors</code> table the names of those with fewer than 20 flavors. This might be compiled into an SQL query such as</p>
<pre><code> select p.name as name from parlors as p
where p.flavors <= 20</code></pre>
<p>The <code>asList</code> function extracts an entire table at once:</p>
<pre><code> sig asList : (TableHandle((|a::Base),_,_)) -> [(|a::Base)]
fun asList(t) {for (z <-- t) [z]}</code></pre>
<p>Thus the following expression gives the same result as the previous query for selecting shops with fewer than 20 flavors, but it does more work outside the database system:</p>
<pre><code> for (p <- asList(parlors))
where (p.flavors <= 20)
[(name = p.name)]</code></pre>
<p>It would use the following simple SQL to get its raw data:</p>
<pre><code> select * from parlors</code></pre>
<p>and the Links runtime system would filter the data itself.</p>
<h3 id="Database-modifications">Database modifications</h3>
<p>Links can also modify database tables using insert, update and delete operations, which work similarly to the corresponding SQL statements.</p>
<p>For example, the Links expression</p>
<pre><code> insert t values (f1, ..., fk) rs</code></pre>
<p>inserts the list of rows <code>rs</code> into the table <code>t</code> where <code>rs</code> must be a list of records with fields <code>f1, ... fk</code>.</p>
<p>The Links expression</p>
<pre><code> update (var r <-- t)
where condition
set (f1 = v1, ..., fn = vn)</code></pre>
<p>updates the rows of table <code>t</code> that satisfy <code>condition</code> by setting each field <code>fi</code> to <code>vi</code>.</p>
<p>The Links expression</p>
<pre><code> delete (var r <-- t)
where condition</code></pre>
<p>deletes the rows of table <code>t</code> that satisfy <code>condition</code>.</p>
<h3 id="Table-constraints">Table constraints</h3>
<p>Database fields can be given two kinds of special features: they can be made <i>read-only</i> and they can be <i>defaulted</i> or given default values when inserting.</p>
<p>A read-only field must not be included in an insert or an update. A defaulted field need not, and cannot, be included in an insert or update command.</p>
<p>To enable these special features on a table field, add a <code>where</code> clause to the table expression that lists field names with the corresponding keyword. For example:</p>
<pre><code> table "people" with (id:Int, name:String, nationality:String)
where id readonly, nationality default from db</code></pre>
<p>This returns a table handle for the table <code>people</code> with fields <code>id</code> and <code>nationality</code>, where the <code>id</code> field cannot be modified through this handle, and <code>nationality</code> has a default value so giving a value is optional when modifying the table.</p>
<p>The type assigned by Links to a table handle has three fields, indicating the <i>readable</i> fields, the <i>writeable</i> fields and the <i>needed</i> fields, in that order:</p>
<pre><code> links>
var t = table "people" with (id:Int, name:String, nationality:String)
where id readonly, nationality default from db;
t = (table people) :
TableHandle((id:Int,name:String,nationality:String),
(name:String,nationality:String),
(name:String))</code></pre>
<p>Only <code>name</code> and <code>nationality</code> are <i>writeable</i>, as <code>id</code> is read-only. Only <code>name</code> is <i>needed</i> when inserting, as <code>nationality</code> has a default and <code>id</code> is read-only.</p>
<h3 id="Database-abstraction">Database abstraction</h3>
<p>Links supports a powerful mode of abstraction over query fragments.</p>
<p>A simple example occurs when you want to filter a table, but using some abstract predicate given by another piece of code. For example, you are writing an API to access some database tables, and you want the API caller to be able to choose how to filter the rows.</p>
<p>A natural way to do this in Links is to represent the filter using a predicate function (one mapping table rows to booleans):</p>
<pre><code> fun selectedShops(pred) {
for (p <-- parlors) where (pred(p)) e
}</code></pre>
<p>In this situation, since the long-arrow generator is used, the programmer demands that the entire comprehension be executed as a single SQL query--even though the predicate on which to filter is not known until runtime.</p>
<p>Still, Links guarantees at compile time that this is achievable--or gives a compile-time error if not. This involves analyzing the program to ensure that callers of <code>selectedShops</code> never pass a function that Links cannot translate to SQL in the context of the above query. If so, an error is generated, usually at the call site, explaining that the function passed was "wild"--the Links term for a function that doesn't translate to SQL.</p>
<p>How to determine at a glance whether your function will translate to SQL? In brief, the only sorts of functions that should fail to translate are those that use "wild" primitives, and recursive functions.</p>
<p>To recognize wild and tame functions in the compiler's output, look at the function arrows. A straight arrow <code>-</code>> indicates a tame function, which can be translated to the database. A squiggly arrow <code>~</code>> indicates a wild function, which cannot be compiled to the database. You can also use these arrow forms in the source, in type annoations, to constrain functions to the way you think they should act (or force the compiler to produce an error message if not).</p>
<p>A comprehension with a long-arrow generator (See <a href="#Using-tables">"Using tables"</a>) implicitly requires the entire comprehension to be translatable to a single SQL query, and this effectively requires every function it calls to be <i>tame</i>. To assert this requirement explicitly, or to make it elsewhere than a comprehension, use the <code>query</code> block form (See <a href="#Query-blocks">"Query blocks"</a>).</p>
<p>Besides the issue of wildness, a query expression is not considered SQL-translatable if its result type is not the type of a flat relation--a list of records with fields of base type (<code>Int</code>, <code>String</code>, <code>Float</code>, and so on).</p>
<h3 id="Query-blocks">Query blocks</h3>
<p>To assert explicitly that an expression--which need not be a comprehension--translates to a query, wrap it in a query block:</p>
<pre><code> query {
e
}</code></pre>
<p>As with long-arrow comprehensions, the expression <code>e</code> must be "tame" and must have relation type: a list of records with fields of base type, or the compiler will give an error.</p>
<p>Use <code>query</code> assertions to offload parts of your computation to the database system, taking advantage of its efficient query-planning facilities.</p>
<h2 id="Structural-pattern-matching">Structural pattern matching</h2>
<p>As well as lists and variants, pattern matching can also be performed on constants.</p>
<pre><code> switch (name) {
case "Ezra" -> "Cooper"
case "Jeremy" -> "Yallop"
case "Phil" -> "Wadler"
case "Sam" -> "Lindley"
}</code></pre>
<p>In common with other strongly-typed functional programming languages such as ML and Haskell, Links supports deep pattern matching.</p>
<pre><code> fun firstChildId(tree) {
switch (tree:mu a.[|Node:(a, b, a) | Leaf|]) {
case Node(Node(_, id, _), _, _) -> Some(id)
case Node(Leaf, _, Node(_, id, _)) -> Some(id)
case _ -> None
}
}</code></pre>
<p>This function takes a labelled binary tree, and returns the id of the first child of the root, if it exists. The wildcard pattern <code>_</code> matches any value. The type annotation is necessary if you want to constrain the function to only operate on labelled binary trees.</p>
<p>Using <code>switch</code> it is possible to dispatch according to the structure of a value. If the structure of a value is already known, then patterns can also be used in other contexts. Patterns can be used to bind function arguments.</p>
<pre><code> fun foo((x=a, y=b)) {a+b}
foo((x=2,y=3))</code></pre>
<p>This example returns <code>5</code>. Patterns can also be used to bind local variables.</p>
<pre><code> {
var language = Language("Links");
var Language(name) = language;
name
}</code></pre>
<p>This example returns <code>"Links"</code>.</p>
<h2 id="Regular-expressions">Regular expressions</h2>
<p>Rudimentary regular-expression (regex) handling is provided for matching string against regex patterns.</p>
<p>A regular expression is written between slashes, as <code>/this.is.a.regex/</code>.</p>
<p>The operator <code>=~</code> tests the string on its left-hand side against the regular expression on its right-hand side. For example:</p>
<pre><code> if ("haystack" =~ /ne+dle/)
print("Found needle in haystack.")
else
print("No needle found in haystack.")</code></pre>
<p>Presently the regex support is somewhat limited; only the following constructions are supported (<code>e</code> standing for any regex):</p>
<pre><code> a (an unadorned character) match exactly that character
[a-z0-9-] match any single character in the given range
. match any single characer
e* match e zero or more times
e+ match e one or more times
e? match an empty string, or e exactly once.
(e) matches whatever e matches</code></pre>
<p>Any of the special characters, <code>*</code> <code>+</code> <code>?</code> <code>(</code> <code>)</code> <code>[</code> and <code>]</code>, can be escaped with a backslash, in which case they match precisely that character, instead of having a special meaning.</p>
<p>Unlike most other regex systems, Links regexes are anchored on both ends. So, to match a substring, you need to add <code>.*</code> at both ends. For example:</p>
<pre><code> links> "Portobello" =~ /bell/
false : Bool
links> "Portobello" =~ /.*bell.*/
true : Bool</code></pre>
<h3 id="Special-feature:-regexes-and-the-database">Special feature: regexes and the database</h3>
<p>Certain uses of regular expressions can be translated to an SQL expression involving the <code>LIKE</code> operator. For example, the expression</p>
<pre><code> for (uni <-- universities)
where (uni.city =~ /.*edinburgh.*/)
[uni]</code></pre>
<p>should translate to an SQL query that selects all those unis from the <code>universities</code> table having <code>edinburgh</code> as a substring of their <code>name</code> column. The query might look like this:</p>
<pre><code> select id from t where t.name like '%edinburgh%'</code></pre>
<h3 id="Limitations">Limitations</h3>
<p>Currently, a regex in Links cannot be treated as a first-class value: a regex can only appear <i>lexically</i> as the right-hand side of a use of the <code>~</code> operator. The left-hand side may be any expression of <code>String</code> type.</p>
<p>There is presently no way to perform regex-based substitutions or to capture parts of a regex match for later use.</p>
<h1 id="Typing">Typing</h1>
<h2 id="Types-in-Links">Types in Links</h2>
<p>Links is a strongly-typed, statically-typed programming language.</p>
<p>This means that every value has a type, and every operation admits just certain types as arguments. The compiler will check that a program uses every value in a way consistent with a type. This way, for example, you can concatenate two lists but you can't concatenate two integers--it wouldn't make sense, and if you try to do it, the compiler will report an error up front. If a program passes the compiler, you can be certain that it doesn't have any type errors (modulo any bugs in the compiler!)</p>
<p>When you use Links through the interactive shell, it tells you the type of every result value. You can use this shell to get familiar with the types of various values. For example:</p>
<pre><code> links> 1 + 1;
2 : Int
links> { var name = "Gallileo"; "Hi, " ++ name };
"Hi, Gallileo" : String
links> (42, "The answer");
(42, "The answer") : (Int, String)
links> [2, 4, 6, 8];
[2, 4, 6, 8] : [Int]
links> ( price = 1.95, drinkName = "Latte" );
(price=1.95,drinkName="Latte") : (drinkName:String,price:Float)
links> Red(7);
Red(7) : [|Red:Int | a|]
links> Blue(7);
Blue(7) : [|Blue:Int | a|]
links> [(42, "The answer"),
(7, "The number of wonders of the world")];
[(42, "The answer"), (7, "The number of wonders of the world")]
: [(Int, String)]</code></pre>
<p>Note that the type of an integer is Int, and the type of a string is String. The <i>pair</i> <code>(42, "The answer")</code> has a type that indicates the first part of the pair is an <code>Int</code> and the second part is a <code>String</code>; this type is written <code>(Int, String)</code>.</p>
<p>A list type is written with square brackets around the type of its elements. Note that <i>all elements of a list must be of the same type</i>. This allows you to apply an operation to an arbitary element of the list and to know what type it is. If you need to mix different types within a list, you can do so by assigning variant tags to each.</p>
<p>By constrast, elements of a tuple can be of the same or of different types, but the number of elements of a tuple is fixed.</p>
<p>The type of a record indicates exactly which fields should be present, and what their types are. The type of a variant tells you what its label is, and what type is contained in that label. (Note that, when you have a function, it may yield a variant type that allows more than one label. Each label has a specific type for its content.)</p>
<p>When you try to evaluate an ill-typed expression, the system will give you a type error:</p>
<pre><code> links> [2, 4, 6, 8, "Who do we appreciate?"];
<stdin>:1: Type error: Cannot unify abstract type 'List' with type 'Int'
In expression: [2, 4, 6, 8, "Who do we appreciate?"].</code></pre>
<h2 id="Base-types">Base types</h2>
<p>The base types offered by Links are</p>
<pre><code> Bool Int Char Float Xml Database</code></pre>
<p>The type <code>String</code> is not really a base type, but rather an alias for <code>[Char]</code> (the type for lists of characters). This means that any general list operation will work on a <code>String</code>.</p>
<h2 id="Type-annotations">Type annotations</h2>
<p>Links can infer type information for any program you give it. This means that you typically don't have to declare any types. But if you get a type error, it may not point to the part of the code where you really made the mistake.</p>
<p>To help the interpreter understand what you intend, and to help it pin down the error to the right place, you can give an optional type annotation on any expression. This is done using the colon as the type ascription operator, as follows:</p>
<pre><code> 2 + 2 : Int # OK
"two plus two" : Int # ERROR</code></pre>
<p>When dealing with constants, as above, the type is always obvious. Type annotation is more useful when dealing with functions, whose type may be inferred in a way that's not obvious. Suppose for example that you have a function h that you know should always return a list of Ints. You can tell the compiler this, and it will check that it is the case:</p>
<pre><code> fun h(x, y) {
f(x) ++ g(y) : [Int]
}</code></pre>
<p>This can be useful because f and g may in fact return types that are compatible (such as <code>[String]</code>), but are not what you expect. Since they are compatible, the function <code>h</code> will be type-correct; but elsewhere in the program, you may get a confusing type error involving <code>h</code>. Providing an annotation for <code>h</code>, like this, will force the compiler to tell you if <code>h</code> does not have the type you expect.</p>
<h2 id="Type-aliases">Type aliases</h2>
<p>Sometimes it is convenient to define an alias for a type in order to avoid having to write out the whole type every time it is used. For instance, suppose you want a type for representing colours:</p>
<pre><code> [|Red | Orange | Yellow | Green | Blue | Indigo | Violet|]</code></pre>
<p>Then you can write:</p>
<pre><code> typename Colour = [|Red | Orange | Yellow | Green | Blue | Indigo | Violet|];</code></pre>
<p>and following this declaration you can use <code>Colour</code> in place of <code>[|Red | Orange | Yellow | Green | Blue | Indigo | Violet|]</code>. For instance, you can now define functions with the following signatures:</p>
<pre><code> sig showColour : (Colour) -> String
sig invertColour : (Colour) -> Colour
sig combineColours : (Colour, Colour) -> Colour</code></pre>
<p>It is also possible to define parameterised type aliases.</p>
<pre><code> links> typename Pair(a, b) = (a, b)
Pair = a,b.(a,b)
links> (1, true) : Pair (?, ?)
(1, true) : Pair (Int, Bool)</code></pre>
<p>It is even possible to parameterise type aliases over row variables.</p>
<pre><code> links> typename R(r::Row) = (x:Int|r);
R = a.(x:Int|a)
links> (x=1, y=true) : R({x:Int, y:Bool});
(x=1,y=true) : R ({ x:Int,y:Bool })</code></pre>
<p>Curly braces indicate that an argument to a type alias is a row rather than a type.</p>
<p>Currently type aliases are only allowed at the top-level.</p>
<h2 id="Type-variables">Type variables</h2>
<p>Type variables in Links are written as lower case names.</p>
<pre><code> sig id : (a) -> a
fun id(x) {x}</code></pre>
<p>We distinguish between <i>rigid</i> type variables and <i>flexible</i> type variables. A <i>rigid</i> type variable (like the <code>a</code> in the <code>id</code> function above) is a proper polymorphic object-level type variable that can be instantiated to any type when its binding function is applied. A <i>flexible</i> type variable (also called a <i>weak</i> type variable or <i>unification</i> type variable) is a monomorphic meta-level variable that will be instantiated to a object-level type by the type inference algorithm. A flexible type variable is indicated by prefixing a type variable with a percent sign <code>%</code>. Flexible type variables are useful if you want to assert the shape of the type of an expression, but you want type inference to fill in some of the type for you.</p>
<pre><code> links> (1, (2, ((3, fun (x) {x}), "a")), true) : (Int, %a, Bool);
(1, (2, ((3, fun), "a")), true) : (Int, (Int, ((Int, (a) -> a), String)), Bool)</code></pre>
<p>If you only want to use a flexible type variable once, then you don't need to name it.</p>
<pre><code> links> (1, (2, ((3, fun (x) {x}), "a")), true) : (Int, %, Bool);
(1, (2, ((3, fun), "a")), true) : (Int, (Int, ((Int, (a) -> a), String)), Bool</code></pre>
<p>A rigid type variable that is only used once is written as <code>_</code>. This notation is also used by the pretty-printer.</p>
<pre><code> links> fun (x) {0};
fun : (_) -> Int</code></pre>
<h2 id="Function-types-and-effects">Function types and effects</h2>
<p>Function typess in Links are annotated with effects. The primitive form of a function type is:</p>
<pre><code> (A1, ..., An) {E}-> B</code></pre>
<p>This is the type of a function that takes n arguments of types <code>A1</code>, ..., <code>An</code>, has effects <code>E</code> and returns values of type <code>B</code>.</p>
<p>The effects <code>E</code> are represented as a <i>row</i> type (as used in record and variant types). If an effect is present then that indicates that it might happen at run-time. If an effects absent then that indicates that it will definitely not happen at run-time.</p>
<p>Currently the only two effects that are tracked in Links are <code>wild</code>, which corresponds to code that cannot be run in the database, and <code>hear:A</code> which corresponds to code that can 'hear' messages of type <code>A</code>. In the future we plan to experiment with tracking other effects.</p>