Skip to content
This repository
Browse code

fixing merge conflict

  • Loading branch information...
commit 3ad027f6dcb95e7d6e87303d92a3add7de313f46 2 parents 90f040e + a71b501
authored

Showing 1 changed file with 955 additions and 118 deletions. Show diff stats Hide diff stats

  1. 1,073  haskell.typechecker.js
1,073  haskell.typechecker.js
... ...
@@ -1,14 +1,259 @@
1 1
 (function (typechecker, ast) {
  2
+
  3
+     var inject = function(arr, f, acc) {
  4
+	 for(var ii in arr) {
  5
+	     acc = f(arr[ii], acc);
  6
+	 }
  7
+	 return acc;
  8
+     };
  9
+
  10
+     var injectRight = function(arr, f, acc) {
  11
+	 for(var ii = arr.length-1; ii >= 0; ii--) {
  12
+	     acc = f(arr[ii], acc);
  13
+	 }
  14
+	 return acc;
  15
+     };
  16
+
  17
+     typechecker.injectRight = injectRight;
  18
+     typechecker.inject = inject;
  19
+
  20
+     var any = function(arr, f) {
  21
+	 return inject(
  22
+	     arr,
  23
+	     function(p, acc) {
  24
+		 return f(p) || acc;
  25
+	     },
  26
+	     false);
  27
+     };
  28
+
  29
+     var elem = function(arr, p) {
  30
+	 return any(
  31
+	     arr,
  32
+	     function(pp) {
  33
+		 return p.compare(pp);
  34
+	     });
  35
+     };
  36
+
  37
+     typechecker.any = any;
  38
+
  39
+     var all = function(arr, f) {
  40
+	 return inject(
  41
+	     arr,
  42
+	     function(p, acc) {
  43
+		 return f(p) && acc;
  44
+	     },
  45
+	     true);
  46
+     };
  47
+
  48
+     typechecker.all = all;     
  49
+
  50
+     var uniqueBy = function(arr, comp) {
  51
+	 var ys = [];
  52
+	 var member = function(x) {
  53
+	     for(var ii in ys) {
  54
+		 if(comp(x, ys[ii])) {
  55
+		     return true;
  56
+		 }
  57
+	     }
  58
+	     return false;
  59
+	 };
  60
+	 for(var ii in arr) {
  61
+	     if(!member(arr[ii])) {
  62
+		 ys.push(arr[ii]);
  63
+	     }
  64
+	 }
  65
+	 return ys;
  66
+     };
  67
+
  68
+     var flatten = function(arr) {
  69
+	 return inject(
  70
+	     arr,
  71
+	     function(a, acc) {
  72
+		 return acc.concat(a);
  73
+	     },
  74
+	     []);
  75
+     };
  76
+
  77
+     typechecker.flatten = flatten;
  78
+
  79
+     var unionBy = function(arr, otherArray, comp) {
  80
+	 return uniqueBy(arr.concat(otherArray), comp);
  81
+     };
  82
+
  83
+     var intersectBy = function(arr, otherArray, comp) {
  84
+	 return inject(
  85
+	     arr,
  86
+	     function(a, acc) {
  87
+		 if(any(
  88
+			otherArray,
  89
+			function(b) {
  90
+			    return comp(a, b);
  91
+			})) {
  92
+		     return acc.concat([a]);
  93
+		 }
  94
+		 return acc;
  95
+	     },
  96
+	     []
  97
+	 );
  98
+     };
  99
+
  100
+     var filter = function(arr, f) {
  101
+	 return inject(
  102
+	     arr,
  103
+	     function(a, acc) {
  104
+		 if(f(a)) {
  105
+		     return acc.concat([a]);
  106
+		 }
  107
+		 return acc;
  108
+	     },
  109
+	     []
  110
+	 );
  111
+     };
  112
+
  113
+     var diff = function(arr, diffArr){
  114
+	 return inject(
  115
+	     arr,
  116
+	     function(a, acc) {
  117
+		 if(!elem(diffArr, a)) {
  118
+		     return acc.concat([a]);
  119
+		 }
  120
+		 return acc;
  121
+	     },
  122
+	     []);
  123
+     };
  124
+
  125
+     typechecker.filter = filter;
  126
+     typechecker.unionBy = unionBy;
  127
+     typechecker.intersectBy = intersectBy;
  128
+
  129
+     ast.Expression.prototype.infer = function(env) {
  130
+	 return this.desugar().infer(env);
  131
+     };
  132
+
  133
+     ast.Constant.prototype.infer = function(env) {
  134
+	 return this.value.infer(env);
  135
+     };
  136
+
2 137
      ast.Num.prototype.infer = function(env) {
3  
-	return new typechecker.Pred(
4  
-	    "Num",
5  
-	    env.newTVar(new typechecker.Star(), env));
  138
+	 var v = typechecker.newTVar(new typechecker.Star(), env);
  139
+	 return {
  140
+	     preds: [new typechecker.Pred("Num", v)],
  141
+	     type: v
  142
+	 };
6 143
      };
7 144
 
8 145
      ast.VariableLookup.prototype.infer = function(env) {
9  
-	 if(env[this.identifier] != undefined) {
10  
-	     return new typechecker.Pred("Num", new typechecker.TVar("a3", new typechecker.Star()));
11  
-	 }
  146
+	 var a = env.lookup(this.identifier);
  147
+	 var inst = a.freshInst(env); 
  148
+	 return {
  149
+	     preds: inst.preds(),
  150
+	     type: inst.t()
  151
+	 };
  152
+     };
  153
+
  154
+     ast.Application.prototype.infer = function(env) {
  155
+	 var fInf = this.func.infer(env);
  156
+	 var argInf = this.arg.infer(env);
  157
+	 var t = env.newTVar(new typechecker.Star());
  158
+	 // return argInf.type;
  159
+	 env.unify(typechecker.fn(argInf.type, t), fInf.type);
  160
+	 return {
  161
+	     preds: fInf.preds.concat(argInf.preds),
  162
+	     type: t
  163
+	 };
  164
+     };
  165
+
  166
+     ast.Case.prototype.infer = function(env) {
  167
+	 var condT = this.expr.infer(env);
  168
+	 env.unify(condT,
  169
+		   typechecker.tBool);
  170
+
  171
+	 var tp = env.newTVar(new typechecker.Star());
  172
+	 var te = env.newTVar(new typechecker.Star());
  173
+	 var ps = [];
  174
+	 this.cases.map(
  175
+	     function(c) {
  176
+		 var patT = c[0].infer(env);
  177
+		 var childEnv = env.createChild();
  178
+		 childEnv.addMany(patT.assumps);
  179
+		 var exprtT = c[1].infer(childEnv);
  180
+		 env.unify(tp, patT);
  181
+		 env.unify(te, exprT);
  182
+		 ps = ps.concat(patT.preds).concat[exprT.preds];
  183
+	     });
  184
+	 return {
  185
+	     preds: ps,
  186
+	     type: te
  187
+	 };
  188
+     };
  189
+
  190
+     ast.ConstantPattern.prototype.infer = function(env) {
  191
+	 return this.value.infer(env);
  192
+     };
  193
+
  194
+     ast.PatternConstructor.prototype.infer = function(env) {
  195
+	 var sc = env.lookup(this.identifier);
  196
+	 var ps = [];
  197
+	 var ts = [];
  198
+	 var as = [];
  199
+	 this.patterns.map(
  200
+	     function(pat) {
  201
+		 var patInf = pat.infer(env);
  202
+		 ps = ps.concat(patInf.preds);
  203
+		 ts.push(patInf.type);
  204
+		 as = as.concat(patInf.assumps);
  205
+	     }
  206
+	 );
  207
+	 var rt = env.newTVar(new typechecker.Star());
  208
+	 var inst = sc.freshInst(env);
  209
+	 var infert = injectRight(
  210
+	     ts,
  211
+	     function(t, acc) {
  212
+		 typechecker.fn(t, acc);
  213
+	     },
  214
+	     rt
  215
+	 );
  216
+	 env.unify(inst.t(), infert);
  217
+	 return {
  218
+	     preds: ps,
  219
+	     assumps: as,
  220
+	     type: rt
  221
+	 };
  222
+     };
  223
+
  224
+     ast.Combined.prototype.infer = function(env) {
  225
+	 var t = this.pattern.infer(env);
  226
+	 return {
  227
+	     preds: t.preds,
  228
+	     assumps: [
  229
+		 new typechecker.Assump(
  230
+		     this.identifier,
  231
+		     typechecker.toScheme(t.type))
  232
+		 ],
  233
+	     type: t.type
  234
+	 };
  235
+     };
  236
+
  237
+     ast.VariableBinding.prototype.infer = function(env) {
  238
+	 var v = typechecker.newTVar(new typechecker.Star(), env);
  239
+	 return {
  240
+	     preds: [],
  241
+	     assumps: [
  242
+		 new typechecker.Assump(
  243
+		     this.identifier,
  244
+		     typechecker.toScheme(v))
  245
+	     ],
  246
+	     type: v
  247
+	 };
  248
+     };
  249
+
  250
+     ast.Wildcard.prototype.infer = function(env) {
  251
+	 var v = typechecker.newTVar(new typechecker.Star(), env);
  252
+	 return {
  253
+	     preds: [],
  254
+	     assumps: [],
  255
+	     type: v
  256
+	 };
12 257
      };
13 258
 
14 259
      /*
@@ -19,15 +264,30 @@
19 264
      typechecker.Star = function() {
20 265
 	 this.toString = function() { return "*"; };
21 266
 	 this.toStringNested = this.toString;
  267
+	 this.equals = function(otherKind) { return otherKind.isStar(); };
  268
+	 this.isStar = function() { return true; };
22 269
      };
23 270
      typechecker.Kfun = function(kind1, kind2) {
24  
-	 this.kind1 = kind1;
25  
-	 this.kind2 = kind2;
  271
+	 this.kind1 = function() { return kind1; };
  272
+	 this.kind2 = function() { return kind2; };
26 273
 	 this.toString = function() {
27  
-	     return kind1.toStringNested() + "->" + kind2.toStringNested();
  274
+	     return this.kind1().toStringNested() +
  275
+		 "->" +
  276
+		 this.kind2().toStringNested();
28 277
 	 };
29 278
 	 this.toStringNested = function() {
30  
-	     return "(" + this.toString() + ")"; };
  279
+	     return "(" + this.toString() + ")";
  280
+	 };
  281
+	 this.isStar = function() { return false; };
  282
+	 this.equals = function(otherKind) {
  283
+	     return !otherKind.isStar() &&
  284
+		 this.kind1().equals(otherKind.kind1()) &&
  285
+		 this.kind2().equals(otherKind.kind2());
  286
+	 };
  287
+     };
  288
+
  289
+     typechecker.Type = function() {
  290
+	 
31 291
      };
32 292
 
33 293
      /*
@@ -36,179 +296,756 @@
36 296
       * 
37 297
       */
38 298
      typechecker.TVar = function(id, kind) {
  299
+	 this.type = function() { return "TVar"; };
39 300
 	 this.toString = function () {
40  
-	     return this.id() + " (" + this.kind() + ")";
  301
+	     return this.id();
41 302
 	 };
  303
+	 this.toStringNested = this.toString;
42 304
 	 this.id = function () { return id; };
43 305
 	 this.kind = function() { return kind; };
44 306
 	 this.apply = function(subst) {
45  
-	     if (subst[this] != undefined) {
46  
-		 return subst[this];
  307
+	     if (subst.lookup(this) != undefined) {
  308
+		 return subst.lookup(this);
47 309
 	     }
48 310
 	     return (new typechecker.TVar(this.id(), this.kind()));
49 311
 	 };
50  
-	 this.tv = function() { return [tyvar]; };
  312
+	 this.tv = function() {
  313
+	     return [new typechecker.TVar(this.id(), this.kind())]; };
  314
+	 this.equals = function (otherTVar) {
  315
+	     return this.id() == otherTVar.id();
  316
+	 };
  317
+	 this.compare = function(otherType) {
  318
+	     return otherType.type() == "TVar" && 
  319
+		 this.id() == otherType.id() &&
  320
+		 this.kind().equals(otherType.kind());
  321
+	 };
  322
+	 this.substWith = function(replaceWith) {
  323
+	     return new typechecker.Subst().add(
  324
+		 this,
  325
+		 replaceWith);
  326
+	 };
  327
+	 this.mgu = function(otherType) {
  328
+	     if(this.compare(otherType)) {
  329
+		 return typechecker.nullSubst();
  330
+	     }
  331
+	     if(elem(otherType.tv(), this)) {
  332
+		     throw "occurs check fails";
  333
+	     }
  334
+	     if(!this.kind().equals(otherType.kind())) {
  335
+		 throw "kinds do not match";
  336
+	     }
  337
+	     return this.substWith(otherType);
  338
+	 };
  339
+	 this.match = function(otherType) {
  340
+	     if(!otherType.kind().equals(this.kind())) {
  341
+		 throw "types do not match";
  342
+	     }
  343
+	     return this.substWith(otherType);
  344
+	 };
  345
+	 this.inst = function(ts) { return this; };
  346
+	 this.hnf = function() { return true; };
51 347
      };
52 348
      
53  
-     /*
54 349
       typechecker.newTVar = function(kind, env) {
55 350
 	 return new typechecker.TVar(env.nextName(), kind);
56  
-     };
57  
-      */
  351
+      };
58 352
 
59 353
      typechecker.TCon = function(id, kind) {
  354
+	 this.type = function() { return "TCon"; };
60 355
 	 this.id = function() { return id; };
61 356
 	 this.kind = function() { return kind; };
62 357
 	 this.apply = function(subst) { return this; };
63 358
 	 this.tv = function() { return []; };
  359
+	 this.equals = function(otherTCon) {
  360
+	     return this.id() == otherTCon.id() &&
  361
+		 this.kind().equals(otherTCon.kind());
  362
+	 };
  363
+	 this.compare = function(otherType) {
  364
+	     return otherType.type() == "TCon" &&
  365
+		 this.id() == otherType.id() &&
  366
+		 this.kind().equals(otherType.kind());
  367
+	 };
  368
+	 this.mgu = function(otherType) {
  369
+	     if(otherType.type() == "TVar") {
  370
+		 return otherType.mgu(this);
  371
+	     }
  372
+	     if(this.compare(otherType)) {
  373
+		 return typechecker.nullSubst();
  374
+	     }
  375
+	     throw "types do not unify";
  376
+	 };
  377
+	 this.match = function(otherType) {
  378
+	     if(otherType.compare(this)) {
  379
+		 return typechecker.nullSubst();
  380
+	     }
  381
+	     throw "types do not match";
  382
+	 };
  383
+	 this.inst = function(ts) { return this; };
  384
+	 this.hnf = function() { return false; };
  385
+	 this.toString = function() {
  386
+	     return this.id();
  387
+	 };
  388
+	 this.toStringNested = this.toString;
64 389
      };
65 390
 
66 391
      typechecker.TAp = function(t1, t2) {
67  
-	 this.kind = function() { return t1.kind().kind2;  };
  392
+	 this.t1 = function() { return t1; };
  393
+	 this.t2 = function() { return t2; };
  394
+	 this.type = function() { return "TAp"; };
  395
+	 this.kind = function() { return this.t1().kind().kind2(); };
68 396
 	 this.apply = function(subst) {
69  
-	     return new typechecker.TAp(t1.apply(),t2.apply());
  397
+	     return new typechecker.TAp(t1.apply(subst),t2.apply(subst));
70 398
 	 };
71 399
 	 this.tv = function() {
72  
-	     return [].concat(t1.tv()).concat(t2.tv()).unique();
  400
+	     if(t1.type() == "TVar" &&
  401
+		t2.type() == "TVar" &&
  402
+		t1.compare(t2)) {
  403
+		 return [t1];
  404
+	     }
  405
+	     return unionBy(
  406
+		 t1.tv(),
  407
+		 t2.tv(),
  408
+		 function(a, b) {
  409
+		     return a.compare(b);
  410
+		 });
  411
+	 };
  412
+	 this.mgu = function(otherType) {
  413
+	     if(otherType.type() == "TAp") {
  414
+		 var s1 = this.t1().mgu(otherType.t1());
  415
+		 var s2 = this.t2().apply(s1).mgu(otherType.t2().apply(s1));
  416
+		 return s1.compose(s2);
  417
+	     }
  418
+	     throw "types do not unify";
  419
+	 };
  420
+	 this.match = function(otherType) {
  421
+	     if(otherType.type() == "TAp") {
  422
+		 var s1 = this.t1().match(otherType.t1());
  423
+		 var s2 = this.t2().match(otherType.t2());
  424
+		 return s1.merge(s1, s2);
  425
+	     }
  426
+	     throw "types do not match";
  427
+	 };
  428
+	 this.compare = function(otherType) {
  429
+	     return otherType.type() == "TAp" &&
  430
+		 this.t1().compare(otherType.t1()) &&
  431
+		 this.t2().compare(otherType.t2());
  432
+	 };
  433
+	 this.inst = function(ts) {
  434
+	     return new typechecker.TAp(
  435
+		 this.t1().inst(ts),
  436
+		 this.t2().inst(ts));
  437
+	 };
  438
+	 this.hnf = function() {
  439
+	     return this.t1().hnf();
  440
+	 };
  441
+	 this.toString = function() {
  442
+	     return this.t1().toStringNested()
  443
+		 + " " + this.t2().toStringNested();
  444
+	 };
  445
+	 this.toStringNested = function() {
  446
+	     return "(" + this.toString() + ")";
73 447
 	 };
74 448
      };
75 449
      typechecker.TGen = function(id) {
76 450
 	 this.id = function() { return id; };
77 451
 	 this.apply = function(subst) { return this; };
78 452
 	 this.tv = function() { return []; };
  453
+	 this.inst = function(ts) { return ts[this.id()]; };
  454
+	 this.toString = function() {
  455
+	     return "g" + this.id();
  456
+	 };
  457
+	 this.toStringNested = this.toString;
  458
+     };
79 459
 
  460
+     typechecker.TVar.prototype = new typechecker.Type();
  461
+     typechecker.TCon.prototype = new typechecker.Type();
  462
+     typechecker.TAp.prototype = new typechecker.Type();
  463
+     typechecker.TGen.prototype = new typechecker.Type();
  464
+
  465
+     typechecker.tArrow = function() {
  466
+	 return new typechecker.TCon(
  467
+	     "(->)",
  468
+	     new typechecker.Kfun(
  469
+		 new typechecker.Star(),
  470
+		 new typechecker.Kfun(
  471
+		     new typechecker.Star(),
  472
+		     new typechecker.Star())));
80 473
      };
81  
-/*
82  
-     typechecker.Class = function(ids, insts) {
83  
-	 this.ids = function() { return ids; };
84  
-	 this.insts = function() { return insts; };
  474
+     typechecker.fn = function(a,b) {
  475
+	 var fn = new typechecker.TAp(
  476
+	     new typechecker.TAp(
  477
+		 typechecker.tArrow(),
  478
+		 a),
  479
+	     b);
  480
+	 fn.toString = function() {
  481
+	     return a.toString() + " -> " + b.toString();
  482
+	 };
  483
+	 fn.toStringNested = fn.toString;
  484
+	 return fn;
85 485
      };
86 486
 
87  
-     typechecker.Inst = function() {
88  
-	 
89  
-     };
90  
-*/
  487
+     typechecker.tBool = 
  488
+	 new typechecker.TCon(
  489
+	     "Bool",
  490
+	     new typechecker.Star());
91 491
 
  492
+     typechecker.Subst = function() {
  493
+	 var mappings = {};
  494
+	 this.add = function(from, to) {
  495
+	     mappings[from.id()] = {
  496
+		 from: from,
  497
+		 to: to
  498
+	     };
  499
+	     return this;
  500
+	 };
  501
+	 this.inject = function(f, acc) {
  502
+	     for(var id in mappings) {
  503
+		 acc = f(mappings[id].from, mappings[id].to, acc);
  504
+	     }
  505
+	     return acc;
  506
+	 };
  507
+	 this.lookup = function(v) {
  508
+	     return (mappings[v.id()] != undefined &&
  509
+		     mappings[v.id()].from.compare(v)) ?
  510
+		 mappings[v.id()].to :
  511
+		 undefined;
  512
+	 };
  513
+	 this.exists = function(v) {
  514
+	     return this.lookup(v) != undefined;
  515
+	 };
  516
+	 this.compose = function(otherSubst) {
  517
+	     var curSubst = this;
  518
+	     var newSubst = this.inject(
  519
+		 function(from, to, acc) {
  520
+		     return acc.add(from, to);
  521
+		 },
  522
+		 new typechecker.Subst());
  523
+	     otherSubst.inject(
  524
+		 function(from, to, acc) {
  525
+		     return acc.add(from, to.apply(curSubst));
  526
+		 },
  527
+		 newSubst);
  528
+	     return newSubst;
  529
+	 };
  530
+	 this.merge = function(otherSubst) {
  531
+	     var newSubst = this.inject(
  532
+		 function(from, to, acc) {
  533
+		     return acc.add(from, to);
  534
+		 },
  535
+		 new typechecker.Subst());
  536
+	     otherSubst.inject(
  537
+		 function(from, to, acc) {
  538
+		     if(acc.exists(from) && !acc.lookup(from).compare(to)) {
  539
+			     throw "merge fails";
  540
+		     }
  541
+		     return acc.add(from, to);
  542
+		 },
  543
+		 newSubst);
  544
+	     return newSubst;
  545
+	 };
  546
+	 this.compare = function(otherSubst) {
  547
+	     var curSubst = this;
  548
+	     return this.inject(
  549
+		 function(from, to, acc) {
  550
+		     return acc &&
  551
+			 otherSubst.lookup(from) != undefined &&
  552
+			 to.compare(otherSubst.lookup(from));
  553
+		 },
  554
+		 true) &&
  555
+		 otherSubst.inject(
  556
+		     function(from, to, acc) {
  557
+			 return acc &&
  558
+			     curSubst.lookup(from) != undefined &&
  559
+			     to.compare(curSubst.lookup(from));
  560
+		     },
  561
+		     true);
  562
+	 };
  563
+	 this.toString = function() {
  564
+	     return this.inject(
  565
+		 function(from, to, acc) {
  566
+		     return from.toString() + ": " + to.toString() + ",";
  567
+		 });
  568
+	 };
  569
+     };
  570
+     typechecker.nullSubst = function() { return new typechecker.Subst({}); };
  571
+     
92 572
      typechecker.Qual = function(preds, t) {
93  
-	 this.pred = function() { return preds; };
  573
+	 this.preds = function() { return preds; };
94 574
 	 this.t = function() { return t; };
  575
+	 this.apply = function(subst) {
  576
+	     return new typechecker.Qual(
  577
+		 preds.map(
  578
+		     function(pred) { return pred.apply(subst); }),
  579
+		 t.apply(subst));
  580
+	 };
  581
+	 this.tv = function() {
  582
+	     return this.preds().map(
  583
+		 function(pred) { return pred.tv(); }
  584
+	     ).concat(this.t().tv());
  585
+	 };
  586
+	 this.compare = function(otherQual) {
  587
+	     var otherPreds = otherQual.preds();
  588
+	     for(var p in preds) {
  589
+		 if(!preds[p].compare(otherPreds[p])) {
  590
+		     return false;
  591
+		 }
  592
+	     }
  593
+	     if(!t.compare(otherQual.t())) {
  594
+		 return false;
  595
+	     }
  596
+	     return true;
  597
+	 };
  598
+	 this.inst = function(ts) {
  599
+	     return new typechecker.Qual(
  600
+		 this.preds().map(
  601
+		     function(pred) { return pred.inst(ts); }),
  602
+		 this.t().inst(ts));
  603
+	 };
  604
+	 this.quantify = function(vs) {
  605
+	     var vss = this.tv().filter(
  606
+		 function(v) {
  607
+		     return elem(vs, v);
  608
+		 });
  609
+	     var ks = vss.map(
  610
+		 function(vv) {
  611
+		     return vv.kind();
  612
+		 });
  613
+	     var i = 0;
  614
+	     var s = inject(
  615
+		 vss,
  616
+		 function(vv, acc) {
  617
+		     acc.add(vv, new typechecker.TGen(i));
  618
+		     i++;
  619
+		     return acc;
  620
+		 });
  621
+	     return new typechecker.Scheme(
  622
+		 ks,
  623
+		 this.apply(s));
  624
+	 };
  625
+	 this.toString = function() {
  626
+	     return this.t().toString();
  627
+	 };
95 628
      };
96 629
 
97  
-     typechecker.Pred = function(class, type) {
98  
-	 this.class = function() { return class; };
  630
+     typechecker.Pred = function(id, type) {
  631
+	 this.id = function() { return id; };
99 632
 	 this.type = function() { return type; };
  633
+	 this.apply = function(subst) { return this.type().apply(subst); };
  634
+	 this.mguPred = function(otherPred) {
  635
+	     if(this.id() == otherPred.id()) {
  636
+		 return this.type().mgu(otherPred.type());
  637
+	     }
  638
+	     throw "classes differ";
  639
+	 };
  640
+	 this.matchPred = function(otherPred) {
  641
+	     if(this.id() == otherPred.id()) {
  642
+		 return this.type().match(otherPred.type());
  643
+	     }
  644
+	     throw "classes differ";
  645
+	 };
  646
+	 this.overlap = function(otherPred) {
  647
+	     try {
  648
+		 this.mguPred(otherPred);
  649
+	     } catch (x) {
  650
+		 return false;
  651
+	     }
  652
+	     return true;
  653
+	 };
  654
+	 this.tv = function() { return this.type().tv(); };
  655
+	 this.compare = function(otherPred) {
  656
+	     return this.id() == otherPred.id() &&
  657
+		 this.type().compare(otherPred.type());
  658
+	 };
  659
+	 this.inst = function(ts) {
  660
+	     return new typechecker.Pred(this.id(), this.type().inst(ts));
  661
+	 };
  662
+	 this.inHnf = function() {
  663
+	     return this.type().hnf();
  664
+	 };
100 665
 	 this.toString = function() {
101  
-	     return this.class().toString() +
102  
-		 " " + 
103  
-		 this.type().id();
  666
+	     return this.id() + " => " + this.type();
104 667
 	 };
105 668
      };
106 669
 
107 670
      typechecker.Scheme = function(kinds, qual) {
108 671
 	 this.kinds = function() { return kinds; };
109 672
 	 this.qual = function() { return qual; };
110  
-	 this.freshInst = function() {};
  673
+	 this.apply = function(subst) {
  674
+	     return new typechecker.Scheme(
  675
+		 this.kinds(),
  676
+		 this.qual().apply(subst));
  677
+	 };
  678
+	 this.tv = function() { return this.qual().tv(); };
  679
+	 this.freshInst = function(env) {
  680
+	     var ts = this.kinds().map(
  681
+		 function(kind) {
  682
+		     return typechecker.newTVar(kind, env);
  683
+		 });
  684
+	     return this.qual().inst(ts);
  685
+	 };
  686
+	 this.toString = function() {
  687
+	     return this.qual().toString();
  688
+	 };
111 689
      };
112 690
 
113 691
      typechecker.toScheme = function(type) {
114  
-	 return new typechecker.Scheme([], new typechecker.Qual([], type));
  692
+	 return new typechecker.Scheme(
  693
+	     [],
  694
+	     new typechecker.Qual(
  695
+		 [],
  696
+		 type));
  697
+     };
  698
+
  699
+     typechecker.Assump = function(id, scheme) {
  700
+	 this.id = function() { return id; };
  701
+	 this.scheme = function() { return scheme; };
  702
+	 this.toString = function() {
  703
+	     return this.id() + " :: " + this.scheme().toString();
  704
+	 };
115 705
      };
116 706
 
117  
-/*
118  
-     typechecker.ClassEnv = function(classes, defaults) {
119  
-	 this.classes = function() { return classes; };
120  
-	 this.defaults = function() { return defaults; };
121  
-	 this.super = function(id) {
122  
-	     return this.classes(id).ids();
  707
+     typechecker.Assumps = function(parent) {
  708
+	 parent = parent == undefined ? { 
  709
+	     lookup: function() {
  710
+		 throw "no such identifier";
  711
+	     }
  712
+	 } : parent;
  713
+	 var as = {};
  714
+	 this.add = function(a) {
  715
+	     as[a.id()] = a.scheme();
  716
+	     return this;
  717
+	 };
  718
+	 this.addMany = function(as) {
  719
+	     var cur = this;
  720
+	     as.map(
  721
+		 function(a) {
  722
+		     cur.add(a);
  723
+		 });
  724
+	     return this;
  725
+	 };
  726
+	 this.lookup = function(id) {
  727
+	     if(as[id] != undefined) {
  728
+		 return as[id];
  729
+	     }
  730
+	     return parent.lookup(id);
123 731
 	 };
124  
-	 this.insts = function(id) {
125  
-	     return this.classes(id).insts();
  732
+	 this.createChild = function() {
  733
+	     return new typechecker.Assumps(this);
126 734
 	 };
127 735
      };
128  
-*/
129 736
 
130  
-     /*
131  
-      * Some built-in types
132  
-      * 
133  
-      */
134  
-     typechecker.tUnit
135  
-	 = new typechecker.TCon("()", new typechecker.Star());
136  
-     typechecker.tChar
137  
-	 = new typechecker.TCon("Char", new typechecker.Star());
138  
-     typechecker.tInt
139  
-	 = new typechecker.TCon("Int", new typechecker.Star());
140  
-     typechecker.tInteger
141  
-	 = new typechecker.TCon("Integer", new typechecker.Star());
142  
-     typechecker.tFloat
143  
-	 = new typechecker.TCon("Float", new typechecker.Star());
144  
-     typechecker.tDouble
145  
-	 = new typechecker.TCon("Double", new typechecker.Star());
146  
-
147  
-     typechecker.tList = new typechecker.TCon(
148  
-	 "[]",
149  
-	 new typechecker.Kfun(new typechecker.Star(),
150  
-			      new typechecker.Star()));
151  
-     typechecker.tArrow = new typechecker.TCon(
152  
-	 "(->)",
153  
-	 new typechecker.Kfun(
154  
-	     new typechecker.Star(),
155  
-	     new typechecker.Kfun(
156  
-		 new typechecker.Star(),
157  
-		 new typechecker.Star())));
158  
-     typechecker.tTuple2 = new typechecker.TCon(
159  
-	 "(,)",
160  
-	 new typechecker.Kfun(
161  
-	     new typechecker.Star(),
162  
-	     new typechecker.Kfun(
163  
-		 new typechecker.Star(),
164  
-		 new typechecker.Star())));
165  
-     /*
166  
-      * Substitutions
167  
-      * 
168  
-      * type Subst [(Tyvar, Type)]
169  
-      * 
170  
-      * We use a map (JavaScript Object) instead
171  
-      * 
172  
-      */
173  
-/*
174  
-     typechecker.nullSubst = {};
175  
-     typechecker.singleSubst = function(u,t) { return {u: t}; };
176  
-     typechecker.composeSubst = function(s1, s2) {
177  
-	 var s3 = {};
178  
-	 for(var u in s2) {
179  
-	     s3[u] = s2[u].apply(s1);
180  
-	 }
181  
-	 for(var u in s1) {
182  
-	     s3[u] = s1[u];
183  
-	 }
184  
-	 return s3;
  737
+
  738
+     typechecker.NameGen = function() {
  739
+	 var curr = 0;
  740
+	 this.nextName = function() {
  741
+	     var ret = curr;
  742
+	     curr++;
  743
+	     return "a" + ret;
  744
+	 };
185 745
      };
186  
-*/
187 746
 
188  
-     typechecker.NameGen = function(startAt) {
189  
-	 this.next = function(env) {
190  
-	     while(env["a" + startAt] != undefined) {
191  
-		 startAt++;
  747
+     typechecker.Klass = function(supers, instances) {
  748
+	 this.supers = function() { return supers; };
  749
+	 this.instances = function() { return instances; };
  750
+     };
  751
+
  752
+     typechecker.KlassEnvironment = function() {
  753
+	 var env = {};
  754
+	 this.lookup = function(id) {
  755
+	     if(this.defined(id)) {
  756
+		 return env[id];
192 757
 	     }
193  
-	     return "a" + startAt;
  758
+	     throw "class not found";
  759
+	 };
  760
+	 this.modify = function(id, klass) {
  761
+	     env[id] = klass;
  762
+	     return this;
  763
+	 };
  764
+	 this.defined = function(id) {
  765
+	     return env[id] != undefined;
  766
+	 };
  767
+	 this.addClass = function(id, supers) {
  768
+	     var cur = this;
  769
+	     if(this.defined(id)) {
  770
+		 throw "class already defined";
  771
+	     }
  772
+	     supers.map(
  773
+		 function(s) {
  774
+		     if(!cur.defined(s)) {
  775
+			 throw "superclass not defined";
  776
+		     }
  777
+		 });
  778
+	     return this.modify(
  779
+		 id,
  780
+		 new typechecker.Klass(
  781
+		     supers,
  782
+		     []));
  783
+	 };
  784
+	 this.addInst = function(ps, p) {
  785
+	     if(!this.defined(p.id())) {
  786
+		 throw "no class for instance";
  787
+	     }
  788
+	     var qs = this.lookup(p.id()).instances().map(
  789
+		 function(inst) {
  790
+		     return inst.t();
  791
+		 });
  792
+	     qs.map(
  793
+		 function(q) {
  794
+		     if(p.overlap(q)) {
  795
+			 throw "overlapping instances";
  796
+		     }
  797
+		 });
  798
+	     return this.modify(
  799
+		 p.id(),
  800
+		 new typechecker.Klass(
  801
+		     this.lookup(p.id()).supers(),
  802
+		     this.lookup(p.id()).instances().concat(
  803
+			 [new typechecker.Qual(ps, p)])));   
  804
+		     
  805
+	 };
  806
+	 this.bySuper = function(pred) {
  807
+	     var cur = this;
  808
+	     return [pred].concat(
  809
+		 flatten(
  810
+		     this.lookup(pred.id()).supers().map(
  811
+			 function(id) {
  812
+			     return cur.bySuper(
  813
+				 new typechecker.Pred(
  814
+				     id,
  815
+				     pred.type()));
  816
+			 }
  817
+		     )));
  818
+	 };
  819
+	 this.byInst = function(pred) {
  820
+	     var ret = undefined;
  821
+	     this.lookup(pred.id()).instances.map(
  822
+		 function(qual) {
  823
+		     if(ret != undefined) {
  824
+			 return;
  825
+		     }
  826
+		     try {
  827
+			 var u = qual.t().matchPred(pred);
  828
+			 ret = qual.preds().map(
  829
+			     function(p) {
  830
+				 return p.apply(u);
  831
+			     });
  832
+		     } catch (x) {
  833
+			 return;
  834
+		     }
  835
+		 }
  836
+	     );
  837
+	     return ret;
194 838
 	 };
195  
-     };
196 839
 
197  
-     typechecker.Environment = function(init) {
198  
-	 if(init != undefined) {
199  
-	     for(i in init) {
200  
-		 this[i]=init[i];
  840
+	 this.entail = function(ps, p) {
  841
+	     var cur = this;
  842
+	     var a = any(
  843
+		 ps.map(
  844
+		     function(pp) {
  845
+			 return cur.bySuper(pp);
  846
+		     }),
  847
+		 function(pps) {
  848
+		     return any(
  849
+			 pps,
  850
+			 function(pp) {
  851
+			     return p.compare(pp);
  852
+			 });
  853
+		 });
  854
+	     var qs = this.byInst(p);
  855
+	     var b = qs == undefined
  856
+		 ? false
  857
+		 : all(
  858
+		     qs,
  859
+		     function(q) {
  860
+			 return cur.entail(ps,q);
  861
+		     });
  862
+	     return a || b;
  863
+	 };
  864
+
  865
+	 this.toHnfs = function(ps) {
  866
+	     return flatten(
  867
+		 ps.map(
  868
+		     function(p) {
  869
+			 return this.toHnf(p);
  870
+		     }));
  871
+	 };
  872
+
  873
+	 this.toHnf = function(p) {
  874
+	     if(p.inHnf()) {
  875
+		 return [p];
201 876
 	     }
202  
-	 }
203  
-	 var gen = new typechecker.NameGen(1);
204  
-	 this.nextName = function() { return gen.next(this); };
205  
-	 this.newTVar = function (kind) {
206  
-	     return new typechecker.TVar(this.nextName(), kind);
  877
+	     var ps = this.byInst(p);
  878
+	     if(ps == undefined) {
  879
+		 throw "context reduction";
  880
+	     }
  881
+	     return this.toHnfs(ps);
207 882
 	 };
  883
+
  884
+	 this.simplify = function(qs) {
  885
+	     var rs = [];
  886
+	     var ps = qs;
  887
+	     while(ps.length != 0) {
  888
+		 if(this.entail(
  889
+			rs.concat(ps.slice(1)),
  890
+			ps.slice(0,1))) {
  891
+		     ps = ps.slice(1);
  892
+		 } else {
  893
+		     rs = ps.slice(0,1).concat(rs);
  894
+		     ps = ps.slice(1);
  895
+		 }
  896
+	     }
  897
+	     return rs;
  898
+	 };
  899
+
  900
+	 this.reduce = function(ps) {
  901
+	     return this.simplify(this.toHnfs(ps));
  902
+	 };
  903
+
  904
+	 this.scEntail = function(ps, p) {
  905
+	     var cur = this;
  906
+	     return any(
  907
+		 ps.map(
  908
+		     function(pp) {
  909
+			 return cur.bySuper(pp);
  910
+		     }),
  911
+		 function(pps) {
  912
+		     return elem(pps, p);
  913
+		 });
  914
+	 };
  915
+     };
  916
+
  917
+     typechecker.ambiguities = function(ce, vars, preds) {
  918
+	 return diff(preds.tv(), vars).map(
  919
+	     function(v) {
  920
+		 return {
  921
+		     type: v,
  922
+		     preds: filter(
  923
+			 ps,
  924
+			 function (vv) {
  925
+			     return elem(preds, vv);
  926
+			 })
  927
+		 };
  928
+	     });
208 929
      };
209 930
 
210  
-     typechecker.emptyEnv = function() {
211  
-	 return new typechecker.Environment();
  931
+     typechecker.numClasses = ["Num", "Fractional", "Integral", "Float",
  932
+			       "Real", "RealFloat", "RealFrac"];
  933
+
  934
+     typechecker.stdClasses = ["Eq", "Ord", "Show", "Read", "Bounded",
  935
+			       "Enum", "Ix", "Functor", "Monad",
  936
+			       "MonadPlus"].concat(typechecker.numClasses);
  937
+
  938
+     typechecker.candidates = function(ce, ambig) {
  939
+	 return all(
  940
+	     ambig.preds,
  941
+	     function(p) {
  942
+		 return p.type().compare(ambig.type);
  943
+	     }) && any(
  944
+		 ambig.preds,
  945
+		 function(p) {
  946
+		     return elem(
  947
+			 typechecker.numClasses,
  948
+			 p.id());
  949
+		 }) && all(
  950
+		     ambig.preds,
  951
+		     function(p) {
  952
+			 return elem(
  953
+			     typechecker.stdClasses,
  954
+			     p.id());
  955
+		     }) ? filter(
  956
+			 ce.defaults(),
  957
+			 function(t) {
  958
+			     return all(
  959
+				 ambig.preds,
  960
+				 function(p) {
  961
+				     return ce.entail(
  962
+					 [],
  963
+					 new typechecker.Pred(
  964
+					     p.id(),
  965
+					     t));
  966
+				 }
  967
+			     );
  968
+			 }) :[]; 
  969
+     };
  970
+     
  971
+     typechecker.defaultPreds = function(ce, ts, ps) {
  972
+	 var ambigs = typechecker.ambiguities(ce, ts, ps);
  973
+	 var candidates = ts.map(
  974
+	     ambigs,
  975
+	     function(t) {
  976
+		 return typechecker.candidates(ce, t);
  977
+		 });
  978
+	 if(any(
  979
+		candidates,
  980
+		function(c) {
  981
+		    return c.length == 0;
  982
+		})) {
  983
+	     throw "cannot resolve ambiguity";
  984
+	 }
  985
+	 return flatten(
  986
+	     candidates.map(
  987
+		 function(ambig) {
  988
+		     return ambig.preds;
  989
+		 }
  990
+	     ));
212 991
      };
213 992
 
  993
+     typechecker.defaultSubst = function(ce, ts, ps) {
  994
+	 var ambigs = typechecker.ambiguities(ce, ts, ps);
  995
+	 var candidates = ts.map(
  996
+	     ambigs,
  997
+	     function(t) {
  998
+		 return typechecker.candidates(ce, t);
  999
+		 });
  1000
+	 if(any(
  1001
+		candidates,
  1002
+		function(c) {
  1003
+		    return c.length == 0;
  1004
+		})) {
  1005
+	     throw "cannot resolve ambiguity";
  1006
+	 }
  1007
+	 var subst = new typechecker.Subst();
  1008
+	 for(var i in ts) {
  1009
+	     subst.add(ts[i], ambigs[i].type);
  1010
+	 }
  1011
+	 return subst;
  1012
+     };
  1013
+
  1014
+     typechecker.Environment = function(assumps, subst, namegen) {
  1015
+	 this.nextName = function() {
  1016
+	     return namegen.nextName();
  1017
+	 };
  1018
+	 this.extSubst = function(otherSubst) {
  1019
+	     subst = subst.compose(otherSubst);
  1020
+	 };
  1021
+	 this.getSubst = function() {
  1022
+	     return subst;
  1023
+	 };
  1024
+	 this.unify = function(t1, t2) {
  1025
+	     var newSubst = t1.apply(
  1026
+		 this.getSubst()).mgu(t2.apply(this.getSubst()));
  1027
+	     this.extSubst(newSubst);
  1028
+	 };
  1029
+	 this.newTVar = function(kind) {
  1030
+	     return typechecker.newTVar(kind, namegen);
  1031
+	 };
  1032
+	 this.add = function(a) {
  1033
+	     assumps.add(a);
  1034
+	     return this;
  1035
+	 };
  1036
+	 this.addMany = function(as) {
  1037
+	     return assumps.addMany(as);
  1038
+	 };
  1039
+	 this.lookup = function(id) {
  1040
+	     return assumps.lookup(id);
  1041
+	 };
  1042
+	 this.createChild = function() {
  1043
+	     return new typechecker.Environment(
  1044
+		 assumps.createChild(),
  1045
+		 subst,
  1046
+		 namegen
  1047
+	     );
  1048
+	 };
  1049
+     };
  1050
+ 
214 1051
 }) (haskell.typechecker, haskell.ast);

0 notes on commit 3ad027f

Please sign in to comment.
Something went wrong with that request. Please try again.