-
Notifications
You must be signed in to change notification settings - Fork 19
/
Lambda-example.html
1118 lines (1117 loc) · 56.7 KB
/
Lambda-example.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
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" >
<title>Lambda</title>
<link href="book.css" rel="stylesheet" type="text/css">
<link href="code.css" rel="stylesheet" type="text/css">
<link rel="home" href="00-Main.html" title="">
</head>
<body>
<a name="Lambda"></a>
<h1>Lambda</h1>
<p>
From Wikipedia:
</p>
<p>
<em>"In mathematical logic and computer science, lambda calculus is a formal
system for function definition, function application and recursion.
The portion of lambda calculus relevant to computation is now called
the untyped lambda calculus. In both typed and untyped versions,
ideas from lambda calculus have found application in the fields of logic,
recursion theory (computability), and linguistics, and have played an
important role in the development of the theory of programming languages
(with untyped lambda calculus being the original inspiration for
functional programming, in particular Lisp, and typed lambda calculi
serving as the foundation for modern type systems)."</em>
</p>
<p>
As another example of use of Xsemantics we also developed a prototype
implementation of a lambda-calculus in XTEXT (we'll show the grammar in the following);
in this lambda-calculus we can specify the type of the parameter of
the abstraction, but we can also leave it empty;
we can then infer the type of each lambda term.
In particular, we infer types using type variables when
the type of a term can be generic.
The types of this lambda-calculus can be basic types
(in this example integer or string), arrow types, and type variables
(denoted by identifiers).
</p>
<p>
The challenging part in writing a type system for this language is
that we need to perform <em>unification</em> in order to infer the <em>most general type</em>
(see, e.g., J. A. Robinson. Computational logic: The unification computation.
Machine Intelligence, 6, 1971.).
</p>
<p>
Again, this is just a tutorial example, but this technique can be used
to infer types in another language implemented in Xtext,
especially for functional languages.
</p>
<a name="LambdaInANutshell"></a>
<h2>Lambda in a nutshell</h2>
<p>
You can think of lambda abstraction as a function definition
(without a name), with a parameter (in this version we consider
one single parameter) and a body, such as
</p>
<p>
<div class="literallayout">
<div class="incode">
<p class="code">
<span class="keyword">lambda</span> x. x<br/>
</p>
</div>
</div>
</p>
<p>
which is the identity function (given an argument it returns the same argument).
Lambda application, which corresponds to function invocation, is denoted
without the parenthesis, thus if we have a lambda abstraction
<span class="inlinecode">M</span> and an argument <span class="inlinecode">N</span> we write <span class="inlinecode">M N</span> to mean
"invoke the function <span class="inlinecode">M</span> passing <span class="inlinecode">N</span> as the argument."
Of course, <span class="inlinecode">M N</span> is a well typed lambda term only if <span class="inlinecode">M</span>
is a function which takes as a parameter of a type <span class="inlinecode">T</span> and
<span class="inlinecode">N</span> is a lambda term with a type conformant to <span class="inlinecode">T</span>.
</p>
<p>
Both of the following definitions with an explicit type for
the parameter are correct:
</p>
<p>
<div class="literallayout">
<div class="incode">
<p class="code">
<span class="keyword">lambda</span> x : <span class="keyword">string</span> . x<br/>
<span class="keyword">lambda</span> x : <span class="keyword">int</span> . x<br/>
</p>
</div>
</div>
</p>
<p>
These two functions have types, respectively,
<span class="inlinecode"><span class="keyword">string</span> -> <span class="keyword">string</span></span> (given a string it returns a string) and
<span class="inlinecode"><span class="keyword">int</span> -> <span class="keyword">int</span></span>. Note that <em>arrow types</em> associate to the right,
thus <span class="inlinecode">a -> b -> c</span> is to be intended as <span class="inlinecode">a -> (b -> c)</span>; otherwise,
we must use parenthesis.
</p>
<p>
Indeed, we can be more general and say that the parameter
<span class="inlinecode">x</span> can be "any" type, using a type variable (similar to Java generics):
</p>
<p>
<div class="literallayout">
<div class="incode">
<p class="code">
<span class="keyword">lambda</span> x : a . x<br/>
</p>
</div>
</div>
</p>
<p>
This function then has type <span class="inlinecode">a -> a</span>; note that since we return the
argument as we received it, then the return type must be the same as
the argument type, thus the type variable <span class="inlinecode">a</span> must be the same in <span class="inlinecode">a -> a</span>.
</p>
<p>
In other cases, we cannot be generic; for instance, consider that in our
language we have the unary operator <span class="inlinecode">-</span> which can be used on integers only.
Then, the function
</p>
<p>
<div class="literallayout">
<div class="incode">
<p class="code">
<span class="keyword">lambda</span> x . -x<br/>
</p>
</div>
</div>
</p>
<p>
imposes <span class="inlinecode">x</span> to be an integer, thus this function has type
<span class="inlinecode"><span class="keyword">int</span> -> <span class="keyword">int</span></span>.
</p>
<p>
Other functions can be partially generic, like the following one
(which makes a little sense, it's used only as an example)
</p>
<p>
<div class="literallayout">
<div class="incode">
<p class="code">
<span class="keyword">lambda</span> x . 10<br/>
</p>
</div>
</div>
</p>
<p>
which has type <span class="inlinecode">a -> <span class="keyword">int</span></span>.
</p>
<p>
We might also let the system infer the type
(and that's what we intend to do with our type system definition).
</p>
<p>
For non trivial cases the type inference is more interesting than the
examples we saw so far; for instance, consider this lambda abstraction
</p>
<p>
<div class="literallayout">
<div class="incode">
<p class="code">
<span class="keyword">lambda</span> x . <span class="keyword">lambda</span> y. x y<br/>
</p>
</div>
</div>
</p>
<p>
which has type <span class="inlinecode">(a -> b) -> a -> b</span>: how can this be inferred?
Informally, <span class="inlinecode">x</span> cannot have any type, since in the body we read
<span class="inlinecode">x y</span> then <span class="inlinecode">x</span> must be a function; for the moment we give it
a generic type <span class="inlinecode">X1 -> X2</span>; what can the type of <span class="inlinecode">y</span> be?
It can be a generic type, say <span class="inlinecode">X3</span>, but since we pass it to <span class="inlinecode">x</span> then
it must have the same type of the argument of <span class="inlinecode">x</span>, thus we require
<span class="inlinecode">X1</span> to be the same as <span class="inlinecode">X3</span>. The result of <span class="inlinecode">x y</span> will have
the same type as the return type of <span class="inlinecode">x</span>, i.e., <span class="inlinecode">X2</span>. Thus,
the above function has the following type:
it takes an argument for the parameter <span class="inlinecode">x</span> of type <span class="inlinecode">X1 -> X2</span>,
and it returns a function (the inner lambda abstraction) which takes
an argument for the parameter <span class="inlinecode">y</span> of type <span class="inlinecode">X1</span> and returns
something of type <span class="inlinecode">X2</span>. Thus, using different (and more readable)
type variable names, <span class="inlinecode">(a -> b) -> a -> b</span>
(we used the parenthesis since by default arrow types associate to the right).
Again, the type variables make the function generic, provided
that the same type is used for all occurrences of <span class="inlinecode">a</span> and the same
type is used for all occurrences of <span class="inlinecode">b</span>.
</p>
<p>
<table>
<tr>
<td>
<span class="inlinecode"><span class="keyword">lambda</span> x .<span class="keyword">lambda</span> y.y x</span>
</td>
<td>
<span class="inlinecode">a -> (a -> b) -> b</span>
</td>
</tr>
<tr>
<td>
<span class="inlinecode"><span class="keyword">lambda</span> f .(<span class="keyword">lambda</span> x.(f (f x)))</span>
</td>
<td>
<span class="inlinecode">(a -> a) -> a -> a</span>
</td>
</tr>
<tr>
<td>
<span class="inlinecode"><span class="keyword">lambda</span> f .<span class="keyword">lambda</span> g.<span class="keyword">lambda</span> x.(f(g x))</span>
</td>
<td>
<span class="inlinecode">(a -> b) -> (c -> a) -> c -> b</span>
</td>
</tr>
</table>
</p>
<p>
Note that there are functions which cannot be typed (at least with
simple type systems we're used to), e.g.,
</p>
<p>
<div class="literallayout">
<div class="incode">
<p class="code">
<span class="keyword">lambda</span> x . x x<br/>
</p>
</div>
</div>
</p>
<p>
cannot be typed, since <span class="inlinecode">x</span> should be a function, say with type
<span class="inlinecode">a -> b</span>, but since we apply <span class="inlinecode">x</span> to <span class="inlinecode">x</span> it should also be of
type <span class="inlinecode">a</span>; however, <span class="inlinecode">a -> b</span> and <span class="inlinecode">a</span> cannot be unified,
since <span class="inlinecode">a</span> occurs in <span class="inlinecode">a -> b</span>.
</p>
<a name="LambdaInXtext"></a>
<h2>Lambda implemented in Xtext</h2>
<p>
This is the grammar for our simple lambda calculus in Xtext:
</p>
<p>
<div class="literallayout">
<div class="incode">
<p class="code">
<span class="keyword">grammar</span> org.eclipse.xsemantics.example.lambda.Lambda <span class="keyword">with</span> org.eclipse.xtext.common.Terminals<br/>
<span class="keyword">generate</span> lambda <span class="string">"http://xsemantics.sf.net/example/lambda/Lambda"</span><br/>
<br/>
Program: term=Term;<br/>
<br/>
<span class="comment">// left associative<br/>
</span>Term: TerminalTerm (=>({Application.fun=<span class="keyword">current</span>} arg=TerminalTerm)*) ;<br/>
<br/>
TerminalTerm <span class="keyword">returns</span> Term:<br/>
<span class="string">'('</span> Term <span class="string">')'</span> |<br/>
Constant |<br/>
Arithmetics |<br/>
Variable |<br/>
Abstraction<br/>
;<br/>
<br/>
Constant: StringConstant | IntConstant ;<br/>
StringConstant: string=STRING;<br/>
IntConstant: int=INT;<br/>
<br/>
Arithmetics: <span class="string">'-'</span> term=Term;<br/>
<br/>
Variable: ref=[Parameter];<br/>
<br/>
Abstraction: <span class="string">'lambda'</span> param=Parameter <span class="string">'.'</span> term=Term ;<br/>
<br/>
Parameter: name=ID (<span class="string">':'</span> type=Type)? ;<br/>
<br/>
<span class="comment">// right associative<br/>
</span>Type: TerminalType ({ArrowType.left = <span class="keyword">current</span>} <span class="string">'->'</span> right=Type)? ;<br/>
<br/>
TerminalType <span class="keyword">returns</span> Type:<br/>
<span class="string">'('</span> Type <span class="string">')'</span> |<br/>
BasicType |<br/>
TypeVariable<br/>
;<br/>
<br/>
BasicType:<br/>
{IntType} <span class="string">'int'</span> |<br/>
{StringType} <span class="string">'string'</span><br/>
;<br/>
<br/>
TypeVariable: typevarName=ID;<br/>
</p>
</div>
</div>
</p>
<a name="LambdaTypeSystem"></a>
<h2>Lambda Type Inference</h2>
<p>
Thus, we want to write the type system definition in Xsemantics for Lambda,
also inferring types (performing unification for inferring the most general type).
</p>
<p>
In the following we will skip import statements.
</p>
<p>
We start with the auxiliary functions and judgments:
</p>
<p>
<div class="literallayout">
<div class="incode">
<p class="code">
<span class="keyword">system</span> org.eclipse.xsemantics.example.lambda.xsemantics.LambdaXsemanticsSystem<br/>
<br/>
<span class="keyword">validatorExtends</span> org.eclipse.xsemantics.example.lambda.validation.AbstractLambdaJavaValidator<br/>
<br/>
<span class="keyword">inject</span> LambdaUtils lambdaUtils<br/>
<br/>
<span class="keyword">auxiliary</span> {<br/>
notoccur(Type type, Type other)<br/>
<span class="keyword">error</span> stringRep(type) + <span class="string">" occurs in "</span> + stringRep(other)<br/>
typesubstitution(TypeSubstitutions substitutions, Type original) : Type<br/>
unify(TypeSubstitutions substitutions, <br/>
Type left, Type right) : UnifyResult<br/>
<span class="keyword">error</span> <span class="string">"cannot unify "</span> + stringRep(left) + <br/>
<span class="string">" with "</span> + stringRep(right)<br/>
}<br/>
<br/>
<span class="keyword">judgments</span> {<br/>
type |- TypeSubstitutions substitutions |> Term term : <span class="keyword">output</span> Type<br/>
paramtype |~ Parameter param : <span class="keyword">output</span> Type<br/>
}<br/>
</p>
</div>
</div>
</p>
<p>
Note that this type system uses a utility class implementing a map
for type substitutions which we will use during type inference
and unification
</p>
<p>
<div class="literallayout">
<div class="incode">
<p class="code">
<span class="keyword">package</span> org.eclipse.xsemantics.example.lambda.xsemantics;<br/>
<br/>
<span class="keyword">public</span> <span class="keyword">class</span> TypeSubstitutions {<br/>
<br/>
<span class="keyword">protected</span> Map<String, Type> substitutions = <span class="keyword">new</span> HashMap<String, Type>();<br/>
<br/>
<span class="keyword">public</span> <span class="keyword">void</span> reset() {<br/>
substitutions.clear();<br/>
}<br/>
<br/>
<span class="keyword">public</span> <span class="keyword">void</span> add(String typeVariableName, Type mapped) {<br/>
substitutions.put(typeVariableName, mapped);<br/>
}<br/>
<br/>
<span class="keyword">public</span> Type mapped(String typeVariableName) {<br/>
<span class="keyword">return</span> substitutions.get(typeVariableName);<br/>
}<br/>
<br/>
<span class="keyword">public</span> Set<Entry<String, Type>> getSubstitutions() {<br/>
<span class="keyword">return</span> substitutions.entrySet();<br/>
}<br/>
}<br/>
</p>
</div>
</div>
</p>
<p>
It uses <span class="inlinecode">UnionResult</span> that is basically an implementation of a pair
of <span class="inlinecode">Type</span>s.
</p>
<p>
Let's start with the auxiliary function implementations
that check that a type variable does NOT occur
in another type term (judgment <em>notoccur</em>, which takes two input parameters):
</p>
<p>
<div class="literallayout">
<div class="incode">
<p class="code">
<span class="keyword">auxiliary</span> notoccur(Type type, Type other) { <span class="keyword">true</span> }<br/>
<br/>
<span class="keyword">auxiliary</span> notoccur(TypeVariable variable, TypeVariable other)<br/>
{<br/>
variable.typevarName != other.typevarName<br/>
}<br/>
<br/>
<span class="keyword">auxiliary</span> notoccur(TypeVariable variable, ArrowType arrowType)<br/>
{<br/>
notoccur(variable, arrowType.left)<br/>
notoccur(variable, arrowType.right)<br/>
}<br/>
</p>
</div>
</div>
</p>
<p>
The base case (which simply always holds) catches all the other situations not handled by
the specific cases; the second case states that
a type variable does not occur in another one, if it has a different
name, and the third one that a type variable does not
in an arrow type if it occurs neither
in the left nor in the right part of the arrow.
</p>
<p>
Now we show the implementation of the auxiliary function <em>typesubstitution</em>, which
takes as input parameters a map for type substitution and the original type
and returns the new type after performing substitutions.
</p>
<p>
<div class="literallayout">
<div class="incode">
<p class="code">
<span class="keyword">auxiliary</span> typesubstitution(TypeSubstitutions substitutions, Type type)<br/>
{<br/>
type<br/>
}<br/>
<br/>
<span class="keyword">auxiliary</span> typesubstitution(TypeSubstitutions substitutions, TypeVariable variable)<br/>
{<br/>
<span class="keyword">var</span> mapped = substitutions.mapped(variable.typevarName)<br/>
<span class="keyword">if</span> (mapped != <span class="keyword">null</span>) {<br/>
<span class="keyword">val</span> result = EcoreUtil::copy(mapped)<br/>
typesubstitution(substitutions, result) <span class="comment">// recursive<br/>
</span> } <span class="keyword">else</span><br/>
variable<br/>
}<br/>
<br/>
<span class="keyword">auxiliary</span> typesubstitution(TypeSubstitutions substitutions, ArrowType arrowType)<br/>
{<br/>
<span class="keyword">var</span> Type subResult<br/>
<span class="keyword">val</span> result = EcoreUtil::copy(arrowType)<br/>
subResult = typesubstitution(substitutions, arrowType.left)<br/>
result.left = subResult<br/>
subResult = typesubstitution(substitutions, arrowType.right)<br/>
result.right = subResult<br/>
result<br/>
}<br/>
</p>
</div>
</div>
</p>
<p>
The general case simply returns the input parameter as the result
(no substitution needed).
When we substitute a type variable we create a new <span class="inlinecode">Type</span> by
cloning the value the type variable maps to (if there's
no existing mapping, it means that there's no need of
substitution, and the result is simply the input argument).
However, we cannot stop here:
a type variable can map to another type variable (see the
cases below for unification) which in turn can be mapped to something
else and so on, thus, we must make sure we apply all the substitutions
that concern a type variable: we apply the substitution recursively
on the result.
</p>
<p>
For instance, if we have the mappings
<span class="inlinecode">X1</span> to <span class="inlinecode">(<span class="keyword">int</span>->X2)</span> and <span class="inlinecode">X2</span> to <span class="inlinecode"><span class="keyword">string</span></span>
and we have apply the substitutions to the the type <span class="inlinecode">X1->X2</span>,
the result must be
<span class="inlinecode">(<span class="keyword">int</span>-><span class="keyword">string</span>)-><span class="keyword">string</span></span>.
</p>
<p>
The substitution for an arrow type simply delegates it to its components
(but again, it clones the original type, and acts on the clone).
</p>
<p>
Cloning is mandatory, as explained in <a href="Lambda-example.html#WhyCloning" title="Go to "Why Cloning?"" >section WhyCloning</a>.
</p>
<p>
Note that, if we do not need to have a reference to the original input type,
the substitution judgment can also be invoked by passing the same
argument both for the input and as the output parameter (as we will see
in the following).
</p>
<p>
The auxiliary function for unification
</p>
<p>
<div class="literallayout">
<div class="incode">
<p class="code">
unify(TypeSubstitutions substitutions, <br/>
Type left, Type right) : Type<br/>
<span class="keyword">error</span> <span class="string">"cannot unify "</span> + stringRep(left) + <br/>
<span class="string">" with "</span> + stringRep(right)<br/>
</p>
</div>
</div>
</p>
<p>
takes the substitutions map, two types and outputs the unified type:
it tries to unify the two input types, and if the unification
succeeds it outputs two new types which are the unified version of the
two input types after performing the substitutions (which are
also recorded in the <em>substitutions</em> parameter).
</p>
<p>
The implementation of this auxiliary function
considers all possible cases that make sense
(the default case simply fails); let's start considering the
simpler ones:
</p>
<p>
<div class="literallayout">
<div class="incode">
<p class="code">
<span class="keyword">auxiliary</span> unify(TypeSubstitutions substitutions, Type t1, Type t2) {<br/>
<span class="comment">// if we get here we cannot unify the two types<br/>
</span> <span class="keyword">fail</span><br/>
<span class="keyword">null</span><br/>
} <br/>
<br/>
<span class="keyword">auxiliary</span> unify(TypeSubstitutions substitutions, StringType t1, StringType t2) <br/>
{<br/>
EcoreUtil.copy(t1)<br/>
}<br/>
<br/>
<span class="keyword">auxiliary</span> unify(TypeSubstitutions substitutions, IntType t1, IntType t2)<br/>
{<br/>
EcoreUtil.copy(t1)<br/>
}<br/>
<br/>
<span class="keyword">auxiliary</span> unify(TypeSubstitutions substitutions, TypeVariable typeVar, BasicType basicType)<br/>
{<br/>
substitutions.add(typeVar.typevarName, basicType)<br/>
EcoreUtil.copy(basicType)<br/>
}<br/>
<br/>
<span class="keyword">auxiliary</span> unify(TypeSubstitutions substitutions, BasicType basicType, TypeVariable typeVar)<br/>
{<br/>
unify(substitutions, typeVar, basicType)<br/>
}<br/>
</p>
</div>
</div>
</p>
<p>
Besides the trivial cases, a type variable unifies with a basic type,
and the type variable is replaced by (a clone) of that basic type (and
the substitution is recorded). Note that we must also consider the
symmetric case.
</p>
<p>
<div class="literallayout">
<div class="incode">
<p class="code">
<span class="keyword">auxiliary</span> unify(TypeSubstitutions substitutions, TypeVariable left, TypeVariable right)<br/>
{<br/>
<span class="comment">// unify both variables with a fresh new variable<br/>
</span> <span class="keyword">val</span> fresh = lambdaUtils.createFreshTypeVariable<br/>
substitutions.add(left.typevarName, fresh)<br/>
substitutions.add(right.typevarName, fresh)<br/>
fresh<br/>
}<br/>
</p>
</div>
</div>
</p>
<p>
When we need to unify two type variables we create a fresh new
type variable (using the utility class <a class="jdoc" href="http://help.eclipse.org/helios/topic/org.eclipse.platform.doc.isv/reference/api/org/eclipse/xsemantics/example/lambda/xsemantics/LambdaUtils.html" title="View JavaDoc"><abbr title="org.eclipse.xsemantics.example.lambda.xsemantics.LambdaUtils" >LambdaUtils</abbr></a>,
and we map both variables to that new fresh variable.
</p>
<p>
<div class="literallayout">
<div class="incode">
<p class="code">
<span class="keyword">auxiliary</span> unify(TypeSubstitutions substitutions, TypeVariable v, ArrowType arrow)<br/>
{<br/>
<span class="comment">// occur check<br/>
</span> notoccur(v, arrow)<br/>
substitutions.add(v.typevarName, arrow)<br/>
EcoreUtil.copy(arrow)<br/>
}<br/>
<br/>
<span class="keyword">auxiliary</span> unify(TypeSubstitutions substitutions, ArrowType arrow, TypeVariable v)<br/>
{<br/>
unify(substitutions, v, arrow)<br/>
}<br/>
<br/>
<span class="keyword">auxiliary</span> unify(TypeSubstitutions substitutions, ArrowType arrow1, ArrowType arrow2)<br/>
{<br/>
<span class="keyword">val</span> newArrow1 = EcoreUtil.copy(arrow1)<br/>
<span class="keyword">val</span> newArrow2 = EcoreUtil.copy(arrow2)<br/>
<span class="keyword">var</span> result = unify(substitutions, arrow1.left, arrow2.left)<br/>
newArrow1.left = EcoreUtil.copy(result)<br/>
newArrow2.left = EcoreUtil.copy(result)<br/>
result = unify(substitutions, arrow1.right, arrow2.right)<br/>
newArrow1.right = EcoreUtil.copy(result)<br/>
newArrow2.right = EcoreUtil.copy(result)<br/>
newArrow1<br/>
}<br/>
</p>
</div>
</div>
</p>
<p>
When we unify a type variable with an arrow type, before substituting
that type variable with the arrow type, we must first check that
the variable does not occur in the arrow type (otherwise the unification
fails). And two arrow types are unified by unifying their components.
</p>
<p>
Now we can start examining the actual typing rules.
</p>
<p>
First of all we need a dedicated judgment for <span class="inlinecode">Param</span>, since it is
not a subclass of <span class="inlinecode">Term</span>:
</p>
<p>
<div class="literallayout">
<div class="incode">
<p class="code">
<span class="keyword">rule</span> ParameterType<br/>
G |~ Parameter param : Type type<br/>
<span class="keyword">from</span> {<br/>
{<br/>
param.type != <span class="keyword">null</span><br/>
type = EcoreUtil::copy(param.type)<br/>
}<br/>
<span class="keyword">or</span><br/>
type = lambdaUtils.createFreshTypeVariable<br/>
}<br/>
</p>
</div>
</div>
</p>
<p>
Remember that we can write the type of abstraction's parameter, and in
that case the type is the clone of the original one; otherwise, we
give the parameter a brand new type variable.
</p>
<p>
The judgment for typing takes as a parameter also the <em>substitutions</em>
mapping table, since, as we will see, when inferring a type, we must also
apply the possible substitutions computed so far.
</p>
<p>
<div class="literallayout">
<div class="incode">
<p class="code">
<span class="keyword">axiom</span> StringConstantType<br/>
G |- TypeSubstitutions substitutions |> <br/>
StringConstant stringConstant : lambdaUtils.createStringType<br/>
<br/>
<span class="keyword">axiom</span> IntConstantType<br/>
G |- TypeSubstitutions substitutions |> <br/>
IntConstant intConstant : lambdaUtils.createIntType<br/>
</p>
</div>
</div>
</p>
<p>
The typing of constants is trivial.
</p>
<p>
For the typing of a variable, one might be tempted to write
</p>
<p>
<div class="literallayout">
<div class="incode">
<p class="code">
<span class="comment">// WRONG!<br/>
</span><span class="keyword">rule</span> VariableType<br/>
G |- TypeSubstitutions substitutions |> <br/>
Variable variable : Type type<br/>
<span class="keyword">from</span> {<br/>
G |~ variable.ref : type<br/>
}<br/>
</p>
</div>
</div>
</p>
<p>
that is, the type of a variable is the type of the referred parameter.
However, this would not work,
since in the meantime we might have collected substitutions for
possible type variables occurring in the type type of the
referred parameter. Thus, the type of a variable, is the
type of the referred parameter AFTER we have applied to it
possible substitutions, that is:
</p>
<p>
<div class="literallayout">
<div class="incode">
<p class="code">
<span class="keyword">rule</span> VariableType<br/>
G |- TypeSubstitutions substitutions |> <br/>
Variable variable : Type type<br/>
<span class="keyword">from</span> {<br/>
type = typesubstitution(substitutions, <br/>
EcoreUtil::copy(<span class="keyword">env</span>(G, variable.ref, Type)))<br/>
}<br/>
</p>
</div>
</div>
</p>
<p>
Note also that we rely on the fact that the type of the parameter is
in the environment (the environment will be updated with such information
later in the typing rule for abstraction).
</p>
<p>
<div class="literallayout">
<div class="incode">
<p class="code">
<span class="keyword">rule</span> ArithmeticsType<br/>
G |- TypeSubstitutions substitutions |> <br/>
Arithmetics arithmetics : IntType intType<br/>
<span class="keyword">from</span> {<br/>
intType = lambdaUtils.createIntType<br/>
G |- substitutions |> arithmetics.term : <span class="keyword">var</span> Type termType<br/>
<span class="comment">// the term type must be unifiable with int type<br/>
</span> unify(substitutions, termType, intType)<br/>
}<br/>
</p>
</div>
</div>
</p>
<p>
The code for <span class="inlinecode">Arithmetics</span> will be integer, however, we must
check whether the type of the subterm has a type which can be
unified with <span class="inlinecode">IntType</span>.
</p>
<p>
<div class="literallayout">
<div class="incode">
<p class="code">
<span class="keyword">rule</span> AbstractionType<br/>
G |- TypeSubstitutions substitutions |> Abstraction abstraction : ArrowType type<br/>
<span class="keyword">from</span> {<br/>
G |~ abstraction.param : <span class="keyword">var</span> Type paramType<br/>
G, abstraction.param <- paramType |- <br/>
substitutions |> abstraction.term : <span class="keyword">var</span> Type termType<br/>
paramType = typesubstitution(substitutions, paramType)<br/>
termType = typesubstitution(substitutions, termType)<br/>
type = lambdaUtils.createArrowType(paramType, termType)<br/>
}<br/>
</p>
</div>
</div>
</p>
<p>
For typing a lambda abstraction we take the type of the parameter and we type the body
of the abstraction after putting the mapping for the type of the parameter in the environment
(see also <a href="XsemanticsSyntax.html#Environment" title="Go to "Rule Environment"" >section Environment</a>).
Then we apply possible substitutions to the type of the parameter and the type of the body,
and we return a brand new arrow type, using the two components.
</p>
<p>
<div class="literallayout">
<div class="incode">
<p class="code">
<span class="keyword">rule</span> ApplicationType<br/>
G |- TypeSubstitutions substitutions |> Application application : Type type<br/>
<span class="keyword">from</span> {<br/>
G |- substitutions |> application.fun : <span class="keyword">var</span> Type funType<br/>
<br/>
<span class="comment">// make sure funType can be unified ArrowType<br/>
</span> <span class="keyword">var</span> arrowType = lambdaUtils.createFreshArrowType<br/>
arrowType = unify(substitutions, funType, arrowType) <span class="keyword">as</span> ArrowType<br/>
<br/>
G |- substitutions |> application.arg : <span class="keyword">var</span> Type argType<br/>
<br/>
<span class="comment">// unify arrow left with the type of the argument<br/>
</span> unify(substitutions, arrowType.left, argType)<br/>
<br/>
<span class="comment">// the result is the arrow right after substitutions<br/>
</span> type = typesubstitution(substitutions, arrowType.right)<br/>
}<br/>
</p>
</div>
</div>
</p>
<p>
For typing a lambda application, we require the left part of the application
to be a function, thus we take its type and we
make sure it can be unified with a generic arrow type.
Then, we take the type of the argument, and we try to unify it with the left part of the arrow type.
If also this unification succeeds, the resulting type is the right part of the arrow type
(after substitutions).
</p>
<p>
Let's see, informally, how these rules infer the type for
</p>
<p>
<div class="literallayout">
<div class="incode">
<p class="code">
<span class="keyword">lambda</span> x. <span class="keyword">lambda</span> f. f -x<br/>
</p>
</div>
</div>
</p>
<p>
To avoid ambiguities with the <span class="inlinecode">-></span> of <span class="inlinecode">ArrowType</span> in the following example we use
<span class="inlinecode">--></span> for substitution mappings (which are shown in <span class="inlinecode">{ }</span>).
Try not to confuse mappings for parameters and mappings representing type variable substitutions,
which have strings as keys. Mappings for the environment are represented as
<span class="inlinecode">key <- value</span>.
</p>
<p>
This is informally the trace of the rules:
</p>
<p>
<div class="literallayout">
<div class="incode">
<p class="code">
* AbstractionType<br/>
** what is the type of x? a fresh type variable X1<br/>
** type the body (<span class="keyword">lambda</span> f. f -x) with environment mapping x <- X1<br/>
*** AbstractionType<br/>
**** what is the type of f? a fresh type variable X2<br/>
**** type the body (f -x) with (additional) environment mapping f <- X2<br/>
***** ApplicationType<br/>
****** what is the type of the left part? the type variable X2<br/>
****** (we used VariableType)<br/>
****** but it must be an arrow type<br/>
****** unify X2 with a fresh arrow type (X3 -> X4)<br/>
****** this will generate the substitution <span class="string">'X2'</span> --> (X3 -> X4)<br/>
****** {<span class="string">'X2'</span> --> (X3 -> X4)}<br/>
****** thus now the type of f is (X3 -> X4)<br/>
****** what is the type of the right part? it is <span class="keyword">int</span><br/>
****** (we used ArithmeticsType, and we unified type of x, X1 with <span class="keyword">int</span>)<br/>
****** {<span class="string">'X2'</span> --> (X3 -> X4), <span class="string">'X1'</span> --> <span class="keyword">int</span>}<br/>
****** try to unify X3 with <span class="keyword">int</span><br/>
****** {<span class="string">'X2'</span> --> (X3 -> X4), <span class="string">'X1'</span> --> <span class="keyword">int</span>, <span class="string">'X3'</span> --> <span class="keyword">int</span>}<br/>
****** thus now the type of f is (<span class="keyword">int</span> -> X4)<br/>
****** the type of the application is X4<br/>
**** apply the substitution to the type of param and body<br/>
**** f of type X2, becomes f of type (<span class="keyword">int</span> -> X4)<br/>
**** the type of body (f -x) becomes X4<br/>
**** the resulting type is then (<span class="keyword">int</span> -> X4) -> X4<br/>
** apply the substitution to the type of param and body<br/>
** x of type X1 becomes x of type <span class="keyword">int</span><br/>
** the body has type (<span class="keyword">int</span> -> X4) -> X4<br/>
** the type of our term is <span class="keyword">int</span> -> (<span class="keyword">int</span> -> X4) -> X4<br/>
</p>
</div>
</div>
</p>
<p>
This type, let's write it for simplicity as <span class="inlinecode"><span class="keyword">int</span> -> (<span class="keyword">int</span> -> a) -> a</span>,
says that we must pass to this lambda term a function which takes an integer,
and a function which takes an integer and returns "any type";
as a result we will have that "any type".
Thus the following lambda application terms are well typed
(remember that application associates to the left):
</p>
<p>
<div class="literallayout">
<div class="incode">
<p class="code">
(<span class="keyword">lambda</span> x. <span class="keyword">lambda</span> f. f -x) (10) (<span class="keyword">lambda</span> y. -y)<br/>
(<span class="keyword">lambda</span> x. <span class="keyword">lambda</span> f. f -x) (1) (<span class="keyword">lambda</span> y. <span class="string">"foo"</span>)<br/>
</p>
</div>
</div>
</p>
<p>
The first one will return <span class="inlinecode">10</span> (actually <span class="inlinecode">--10</span>), the second one <span class="inlinecode"><span class="string">"foo"</span></span>.
</p>
<a name="WhyCloning"></a>
<h3>Why Cloning?</h3>
<p>
Remember that the types we are manipulating might have been
explicitly specified in the text of the program by the programmer,
thus, if we did not use clones, during substitutions, we would directly
modifying the AST of the original program, which is not what we want.
</p>
<a name="LambdaChecking"></a>
<h2>Lambda Type Checking</h2>
<p>
Now that we wrote all the rules for inferring types of Lambda terms,
we can write a checkrule (see <a href="XsemanticsSyntax.html#CheckRules" title="Go to "Rules for Validator: checkrule"" >section CheckRules</a>) that says that a Lambda <span class="inlinecode">Program</span>
is correct if we can assign a type to the term (starting from an empty environment):
</p>
<p>
<div class="literallayout">
<div class="incode">
<p class="code">
<span class="keyword">checkrule</span> CheckProgram <span class="keyword">for</span><br/>
Program program<br/>
<span class="keyword">from</span> {<br/>
lambdaUtils.resetCounter<br/>
<span class="comment">// if we can type the program term<br/>
</span> <span class="keyword">empty</span> |- <span class="keyword">new</span> TypeSubstitutions() |> program.term : <span class="keyword">var</span> Type type<br/>
}<br/>
</p>
</div>
</div>
</p>
<p>
The invocation of <span class="inlinecode">resetCounter</span> is just to reset the counter used by
<a class="jdoc" href="http://help.eclipse.org/helios/topic/org.eclipse.platform.doc.isv/reference/api/org/eclipse/xsemantics/example/lambda/xsemantics/LambdaUtils.html" title="View JavaDoc"><abbr title="org.eclipse.xsemantics.example.lambda.xsemantics.LambdaUtils" >LambdaUtils</abbr></a> to create fresh
type variables.
</p>
<a name="LambdaCustomization"></a>
<h2>Customizations for Lambda</h2>
<p>
Since type variables during the type inference have the form <span class="inlinecode">X<number></span> which
makes it hard to visually interpret an inferred type, we use a custom <a class="jdoc" href="http://help.eclipse.org/helios/topic/org.eclipse.platform.doc.isv/reference/api/org/eclipse/xsemantics/runtime/StringRepresentation.html" title="View JavaDoc"><abbr title="org.eclipse.xsemantics.runtime.StringRepresentation" >StringRepresentation</abbr></a>,
namely <a class="jdoc" href="http://help.eclipse.org/helios/topic/org.eclipse.platform.doc.isv/reference/api/org/eclipse/xsemantics/example/lambda/xsemantics/LambdaStringRepresentationWithTypeBeautifier.html" title="View JavaDoc"><abbr title="org.eclipse.xsemantics.example.lambda.xsemantics.LambdaStringRepresentationWithTypeBeautifier" >LambdaStringRepresentationWithTypeBeautifier</abbr></a>,
which relies on <a class="jdoc" href="http://help.eclipse.org/helios/topic/org.eclipse.platform.doc.isv/reference/api/org/eclipse/xsemantics/example/lambda/xsemantics/LambdaTypeBeautifier.html" title="View JavaDoc"><abbr title="org.eclipse.xsemantics.example.lambda.xsemantics.LambdaTypeBeautifier" >LambdaTypeBeautifier</abbr></a>: this
will consistently replace type variables in an inferred type with letters.
For instance, <span class="inlinecode">X1 -> X3 -> (X4 -> X3)</span> would become <span class="inlinecode">a -> b -> (c -> b)</span>.
</p>
<p>
Another customization that we perform in this example, is the way error markers
will be generated.
</p>
<p>
For instance, due to the way error markers are generated
(<a href="XsemanticsSyntax.html#ErrorGeneration" title="Go to "Error Marker Generation"" >section ErrorGeneration</a>), if we have the following code
</p>
<p>
<div class="literallayout">
<div class="incode">
<p class="code">
<span class="keyword">lambda</span> f . -<span class="string">'f'</span><br/>
</p>
</div>
</div>
</p>
<p>
we would get an error since the rule <em>ArithmeticsType</em>
cannot be applied. However, we would like also to know why
it cannot be applied, i.e., because the string type of the string
literal <span class="inlinecode"><span class="string">'f'</span></span> cannot be unified with the int type required
by <em>ArithmeticsType</em>.
</p>
<p>
We can fix this by injecting a custom
<a class="jdoc" href="http://help.eclipse.org/helios/topic/org.eclipse.platform.doc.isv/reference/api/org/eclipse/xsemantics/runtime/validation/XsemanticsValidatorFilter.html" title="View JavaDoc"><abbr title="org.eclipse.xsemantics.runtime.validation.XsemanticsValidatorFilter" >XsemanticsValidatorFilter</abbr></a>,
so that it also shows the rules which failed from that point on:
</p>
<p>
<div class="literallayout">
<div class="incode">
<p class="code">
<span class="keyword">class</span> LambdaValidatorFilter <span class="keyword">extends</span> XsemanticsValidatorFilter {<br/>
<br/>
@Inject <span class="keyword">extension</span> TraceUtils<br/>
<br/>
<span class="keyword">override</span> filterRuleFailedExceptions(RuleFailedException e) {<br/>
<span class="keyword">val</span> inner = e.innermostRuleFailedExceptionWithNodeModelSources<br/>
<span class="keyword">if</span> (inner != null)<br/>
<span class="keyword">return</span> inner.failureAsList<br/>
<span class="keyword">else</span> <span class="comment">// we must return at least a failure, so we default to the passed one<br/>
</span> <span class="keyword">return</span> Lists::newArrayList(e)<br/>
}<br/>
}
</p>
</div>
</div>
</p>
<a name="LambdaTypeInferenceIDE"></a>
<h2>Use of Type Inference in the IDE</h2>
<p>
We can also use the generated Java code for the inference type system to create an editor popup
action (for the editor of Lambda) to automatically infer types and add the types in the program text,
in particular we set the types of the parameters of abstractions.
Most of the code we show here deals with Eclipse plugin development:
the part which uses the code of the type system generated by Xsemantics is minimal.
</p>
<p>
This is done in the class <a class="jdoc" href="http://help.eclipse.org/helios/topic/org.eclipse.platform.doc.isv/reference/api/org/eclipse/xsemantics/example/lambda/xsemantics/LambdaTypeModifier.html" title="View JavaDoc"><abbr title="org.eclipse.xsemantics.example.lambda.xsemantics.LambdaTypeModifier" >LambdaTypeModifier</abbr></a>
(you can see the complete code in the sources of the Lambda example); we show here just the main parts:
</p>
<p>
<div class="literallayout">
<div class="incode">
<p class="code">
<span class="keyword">public</span> <span class="keyword">class</span> LambdaTypeModifier {<br/>
<br/>
@Inject<br/>
<span class="keyword">protected</span> LambdaXsemanticsSystem typeSystem; <span class="comment">// generated by Xsemantics<br/>
</span><br/>
@Inject<br/>
<span class="keyword">protected</span> Provider<LambdaTypeBeautifier> lambdaTypeBeautifierProvider;<br/>
<br/>
<span class="keyword">public</span> RuleFailedException setAllTypes(Term term) {<br/>
Result<Type> result = typeSystem.type(<span class="keyword">new</span> TypeSubstitutions(),<br/>
LambdaTermUtils.cloneWithoutTypes(term));<br/>
<span class="keyword">if</span> (result.getRuleFailedException() != null)<br/>
<span class="keyword">return</span> result.getRuleFailedException();<br/>
Type inferredType = result.getValue();<br/>
beautifyType(inferredType);<br/>
setAllTypes(term, inferredType);<br/>
<span class="keyword">return</span> null;<br/>
}<br/>
<br/>
<span class="keyword">protected</span> <span class="keyword">void</span> beautifyType(Type paramType) {<br/>
lambdaTypeBeautifierProvider.get().beautifyTypeVariables(paramType);<br/>
}<br/>
...<br/>
</p>
</div>
</div>
</p>
<p>