Skip to content

Commit

Permalink
Merge pull request #154 from plaid/dc-sanctuary-def
Browse files Browse the repository at this point in the history
  • Loading branch information
davidchambers committed Feb 25, 2016
2 parents 50740e3 + af94ea5 commit aa90986
Show file tree
Hide file tree
Showing 4 changed files with 106 additions and 37 deletions.
2 changes: 1 addition & 1 deletion bower.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
],
"dependencies": {
"ramda": "0.19.x",
"sanctuary-def": "0.3.x"
"sanctuary-def": "0.4.x"
},
"ignore": [
"/.git/",
Expand Down
125 changes: 90 additions & 35 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,44 @@
//.
//. `Number` is the sole inhabitant of the TypeRep Number type.
//.
//. ## Type checking
//.
//. Sanctuary functions are defined via [sanctuary-def][] to provide run-time
//. type checking. This is tremendously useful during development: type errors
//. are reported immediately, avoiding circuitous stack traces (at best) and
//. silent failures due to type coercion (at worst). For example:
//.
//. ```javascript
//. S.inc('XXX');
//. // ! TypeError: ‘inc’ expected a value of type FiniteNumber as its first argument; received "XXX"
//. ```
//.
//. Compare this to the behaviour of Ramda's unchecked equivalent:
//.
//. ```javascript
//. R.inc('XXX');
//. // => '1XXX'
//. ```
//.
//. There is a performance cost to run-time type checking. One may wish to
//. disable type checking in certain contexts to avoid paying this cost.
//. There are actually two versions of the Sanctuary module: one with type
//. checking; one without. The latter is accessible via the `unchecked`
//. property of the former.
//.
//. When application of `S.unchecked.<name>` honours the function's type
//. signature the result will be the same as if `S.<name>` had been used
//. instead. Otherwise, the behaviour is unspecified.
//.
//. In Node, one could use an environment variable to determine which version
//. of the Sanctuary module to use:
//.
//. ```javascript
//. const S = process.env.NODE_ENV === 'production' ?
//. require('sanctuary').unchecked :
//. require('sanctuary');
//. ```
//.
//. ## API

/* global define, self */
Expand All @@ -123,19 +161,51 @@

'use strict';

var S = {};

var _ = R.__;

var sentinel = {};

// _type :: a -> String
var _type = function(x) {
return x != null && R.type(x['@@type']) === 'String' ? x['@@type']
: R.type(x);
};

// compose2 :: ((b -> c), (a -> b)) -> a -> c
var compose2 = function(f, g) {
return function(x) {
return f(g(x));
};
};

// compose3 :: ((b -> c), (a -> b), a) -> c
var compose3 = function(f, g, x) {
return f(g(x));
};

// filter :: (Monad m, Monoid m) => ((a -> Boolean), m a) -> m a
var filter = function(pred, m) {
return m.chain(function(x) {
return pred(x) ? m.of(x) : m.empty();
});
};

// hasMethod :: String -> Any -> Boolean
var hasMethod = function(name) {
return function(x) {
return x != null && typeof x[name] === 'function';
};
};

// inspect :: -> String
var inspect = /* istanbul ignore next */ function() {
return this.toString();
};

// negativeZero :: a -> Boolean
var negativeZero = R.either(R.equals(-0),
R.equals(new Number(-0))); // jshint ignore:line

// Accessible :: TypeClass
var Accessible = $.TypeClass(
'sanctuary/Accessible',
Expand Down Expand Up @@ -197,7 +267,7 @@
var r = $.TypeVariable('r');

// $Either :: Type -> Type -> Type
var $Either = S.EitherType = $.BinaryType(
var $Either = $.BinaryType(
'sanctuary/Either',
function(x) { return x != null && x['@@type'] === 'sanctuary/Either'; },
function(either) { return either.isLeft ? [either.value] : []; },
Expand All @@ -219,7 +289,7 @@
);

// $Maybe :: Type -> Type
var $Maybe = S.MaybeType = $.UnaryType(
var $Maybe = $.UnaryType(
'sanctuary/Maybe',
function(x) { return x != null && x['@@type'] === 'sanctuary/Maybe'; },
function(maybe) { return maybe.isJust ? [maybe.value] : []; }
Expand Down Expand Up @@ -250,7 +320,14 @@
$.ValidNumber
]);

var def = $.create(env);
// createSanctuary :: Boolean -> Module
var createSanctuary = function(checkTypes) {

// To avoid excessive indentation this function's body is not indented.

var S = {EitherType: $Either, MaybeType: $Maybe};

var def = $.create(checkTypes, env);

var method = function(name, constraints, types, _f) {
var f = def(name, constraints, types, _f);
Expand All @@ -259,36 +336,6 @@
});
};

// _type :: a -> String
var _type = function(x) {
return x != null && R.type(x['@@type']) === 'String' ? x['@@type']
: R.type(x);
};

var compose2 = function(f, g) {
return function(x) {
return f(g(x));
};
};

var compose3 = function(f, g, x) {
return f(g(x));
};

var filter = function(pred, m) {
return m.chain(function(x) {
return pred(x) ? m.of(x) : m.empty();
});
};

var inspect = /* istanbul ignore next */ function() {
return this.toString();
};

// negativeZero :: a -> Boolean
var negativeZero = R.either(R.equals(-0),
R.equals(new Number(-0))); // jshint ignore:line

//. ### Classify

//# type :: a -> String
Expand Down Expand Up @@ -2900,6 +2947,14 @@

return S;

};

// Export two versions of the Sanctuary module: one with type checking;
// one without.
var S = createSanctuary(true);
S.unchecked = createSanctuary(false);
return S;

}));

//. [Apply]: https://github.com/fantasyland/fantasy-land#apply
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
},
"dependencies": {
"ramda": "0.19.x",
"sanctuary-def": "0.3.x"
"sanctuary-def": "0.4.x"
},
"devDependencies": {
"doctest": "0.10.x",
Expand Down
14 changes: 14 additions & 0 deletions test/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4482,3 +4482,17 @@ describe('string', function() {
});

});

describe('unchecked', function() {

it('has the same properties as the top-level module', function() {
eq(R.sortBy(S.I, R.keys(S.unchecked)),
R.sortBy(S.I, R.without(['unchecked'], R.keys(S))));
});

it('provides functions which do not perform type checking', function() {
eq(S.unchecked.inc(42), S.inc(42));
eq(S.unchecked.inc('XXX'), 'XXX1');
});

});

0 comments on commit aa90986

Please sign in to comment.