Skip to content

Instantly share code, notes, and snippets.

@josejuan
Created February 23, 2015 12:01
Show Gist options
  • Save josejuan/a068b2cef30078fd46cd to your computer and use it in GitHub Desktop.
Save josejuan/a068b2cef30078fd46cd to your computer and use it in GitHub Desktop.
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