Created
          February 23, 2015 12:01 
        
      - 
      
- 
        Save josejuan/a068b2cef30078fd46cd to your computer and use it in GitHub Desktop. 
  
    
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      Learn more about bidirectional Unicode characters
    
  
  
    
  | var Class = function (name, ifaces, foldl1_acc) { | |
| return { name: name | |
| , ifaces: ifaces | |
| , foldl1_acc // this is my magic trick! :) but is not generic :( | |
| }; | |
| }; | |
| var Type = function ( name | |
| , product // Type1 x Type2 x ... x TypeN | |
| ) { | |
| var type = { name: name | |
| , product: product | |
| }; | |
| type.make = function ( productValues ) { | |
| return { type: type | |
| , product: productValues // check: length, ... | |
| }; | |
| }; | |
| return type; | |
| }; | |
| // instance as new types; we can implement `instace Class Type where` using javascript prototyping | |
| var NewType = function (name, iclass, btype, maybeImplementation) { | |
| var type = { name: name | |
| , product: btype.product | |
| }; | |
| type.make = function (productValues) { | |
| var bvalue = btype.make(productValues); | |
| bvalue.type = type; | |
| for(var i in iclass.ifaces) { | |
| var method = iclass.ifaces[i]; | |
| var overrideImp = maybeImplementation[method]; | |
| if(typeof overrideImp == "function") { | |
| bvalue[method] = overrideImp; | |
| } else { | |
| bvalue[method] = | |
| function (aproduct) { | |
| aproduct = aproduct || {product: []}; | |
| var currentAcc = null; | |
| for(var j in this.product) { | |
| var subproduct = this.product[j]; | |
| var asubproduct = aproduct.product[j]; | |
| var derivedMethod = subproduct[method]; | |
| if(typeof derivedMethod != "function") | |
| throw ("BOOM! Cannot derive `" + iclass.name + "`, derived type `" + subproduct.type.name + "` not implement that class!"); | |
| currentValue = derivedMethod.call(subproduct, asubproduct); | |
| currentAcc = currentAcc == null ? currentValue : iclass.foldl1_acc(currentAcc, currentValue); | |
| } | |
| return currentAcc; | |
| }; | |
| } | |
| } | |
| return bvalue; | |
| }; | |
| return type; | |
| }; | |
| var Instance = NewType; // nice alias :) | |
| // Like #Int in Haskell | |
| var pureInt = (function () { | |
| var pureIntType = Type("PureInt", []); | |
| pureIntType.make = function (x) { | |
| return { type: pureIntType | |
| , product: [x] | |
| }; | |
| }; | |
| return pureIntType; | |
| })(); | |
| // some generic interfaces Magic deriving rules! | |
| var Eq = Class("Eq" , ["equalTo" ], function (a, x) { return a && x }); | |
| var Ord = Class("Ord" , ["compareTo"], function (a, x) { return a != 0 ? a : x }); | |
| var Show = Class("Show", ["show" ], function (a, x) { return a + "; " + x }); | |
| // instances with explicit implementations (one useful Int type from the pure one #Int) | |
| var IntEq = NewType("IntEq" , Eq , pureInt, { equalTo : function (pureIntB) { return this.product[0] == pureIntB.product[0] } }); | |
| var IntOrd = NewType("IntOrd" , Ord , IntEq , { compareTo: function (pureIntB) { return this.product[0] - pureIntB.product[0] } }); | |
| var IntShow = NewType("IntShow", Show, IntOrd , { show : function () { return "" + this.product[0] } }); | |
| var Int = IntShow; | |
| // Let `Int` instancing `Eq`, `Ord` and `Show` classes, then: | |
| var n = function (x) { return Int.make(x) }; // alias | |
| // testing Int type | |
| console.log( n(4).equalTo(n(5)) ); // false | |
| console.log( n(3).equalTo(n(3)) ); // true | |
| console.log( n(4).compareTo(n(5)) ); // -1 | |
| console.log( n(5).compareTo(n(3)) ); // 2 | |
| console.log( n(2).compareTo(n(2)) ); // 0 | |
| console.log( n(1234).show() ); // "1234" | |
| // Int tuple with all auto-derived!!!! | |
| var TupleInt = Instance("TupleIntEq" , Eq, | |
| Instance("TupleIntOrd" , Ord, | |
| Instance("TupleIntShow", Show, Type("TupleInt_", [Int, Int]), {}), {}), {}); | |
| // aliases | |
| var tup = function (a, b) { return TupleInt.make(a, b) }; | |
| var itup = function (a, b) { return TupleInt.make([Int.make(a), Int.make(b)]) }; | |
| var ta = itup(3, 5); | |
| var tb = itup(2, 7); | |
| console.log( ta.equalTo(tb) ); // false | |
| console.log( tb.equalTo(tb) ); // true | |
| console.log( ta.compareTo(tb) ); // 1 | |
| console.log( tb.compareTo(ta) ); // -1 | |
| console.log( ta.compareTo(ta) ); // 0 | |
| console.log( ta.show() ); // "3; 5" | |
| console.log( tb.show() ); // "2; 7" | |
  
    Sign up for free
    to join this conversation on GitHub.
    Already have an account?
    Sign in to comment