Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

require environments to actually be of type ‘Array Type’ #124

Merged
merged 1 commit into from
Mar 4, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ lint:
--global module \
--global require \
--global self \
--rule 'max-len: [error, {code: 79, ignorePattern: "^ *//(#|[.] //) ", ignoreUrls: true}]' \
--rule 'max-len: [error, {code: 79, ignorePattern: "^ *//(# |[.] // |[.] - <code>)", ignoreUrls: true}]' \
-- index.js
$(ESLINT) \
--env node \
Expand Down
100 changes: 58 additions & 42 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,30 @@
//. const env = $.env.concat([Integer, NonZeroInteger]);
//. ```
//.
//. Type constructors such as `List :: Type -> Type` cannot be included in
//. an environment as they're not of the correct type. One could, though,
//. use a type constructor to define a fixed number of concrete types:
//.
//. ```javascript
//. // env :: Array Type
//. const env = $.env.concat([
//. List($.Number), // :: Type
//. List($.String), // :: Type
//. List(List($.Number)), // :: Type
//. List(List($.String)), // :: Type
//. List(List(List($.Number))), // :: Type
//. List(List(List($.String))), // :: Type
//. ]);
//. ```
//.
//. Not only would this be tedious, but one could never enumerate all possible
//. types as there are infinitely many. Instead, one should use [`Unknown`][]:
//.
//. ```javascript
//. // env :: Array Type
//. const env = $.env.concat([List($.Unknown)]);
//. ```
//.
//. The next step is to define a `def` function for the environment:
//.
//. ```javascript
Expand Down Expand Up @@ -408,15 +432,6 @@
return BinaryType(name, functionUrl(name), test, _1, _2);
}

// applyParameterizedTypes :: Array Type -> Array Type
function applyParameterizedTypes(types) {
return Z.map(function(x) {
return typeof x === 'function' ?
x.apply(null, Z.map(K(Unknown), range(0, x.length))) :
x;
}, types);
}

//. ### Types
//.
//. Conceptually, a type is a set of values. One can think of a value of
Expand Down Expand Up @@ -701,9 +716,20 @@

//# Unknown :: Type
//.
//. Type used internally to represent missing type information. The type of
//. `[]`, for example, is `Array ???`. This type is exported solely for use
//. by other Sanctuary packages.
//. Type used to represent missing type information. The type of `[]`,
//. for example, is `Array ???`.
//.
//. May be used with type constructors when defining environments. Given a
//. type constructor `List :: Type -> Type`, one could use `List($.Unknown)`
//. to include an infinite number of types in an environment:
//.
//. - `List Number`
//. - `List String`
//. - `List (List Number)`
//. - `List (List String)`
//. - `List (List (List Number))`
//. - `List (List (List String))`
//. - `...`
var Unknown = new _Type(UNKNOWN, '', '', always2('???'), K(true), [], {});

//# ValidDate :: Type
Expand All @@ -726,34 +752,34 @@
//.
//. An array of [types][]:
//.
//. - [`AnyFunction`][]
//. - [`Arguments`][]
//. - [`Array`][]
//. - [`Boolean`][]
//. - [`Date`][]
//. - [`Error`][]
//. - [`Null`][]
//. - [`Number`][]
//. - [`Object`][]
//. - [`RegExp`][]
//. - [`StrMap`][]
//. - [`String`][]
//. - [`Undefined`][]
var env = applyParameterizedTypes([
//. - <code><a href="#AnyFunction">AnyFunction</a></code>
//. - <code><a href="#Arguments">Arguments</a></code>
//. - <code><a href="#Array">Array</a>(<a href="#Unknown">Unknown</a>)</code>
//. - <code><a href="#Boolean">Boolean</a></code>
//. - <code><a href="#Date">Date</a></code>
//. - <code><a href="#Error">Error</a></code>
//. - <code><a href="#Null">Null</a></code>
//. - <code><a href="#Number">Number</a></code>
//. - <code><a href="#Object">Object</a></code>
//. - <code><a href="#RegExp">RegExp</a></code>
//. - <code><a href="#StrMap">StrMap</a>(<a href="#Unknown">Unknown</a>)</code>
//. - <code><a href="#String">String</a></code>
//. - <code><a href="#Undefined">Undefined</a></code>
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've pushed a rendered version.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why the raw HTML?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I want to generate…

rather than…

and the only way to have two links inside a <code> element is to use HTML.

var env = [
AnyFunction,
Arguments,
Array_,
Array_(Unknown),
Boolean_,
Date_,
Error_,
Null,
Number_,
Object_,
RegExp_,
StrMap,
StrMap(Unknown),
String_,
Undefined
]);
];

// Type :: Type
var Type = NullaryType(
Expand Down Expand Up @@ -1201,8 +1227,7 @@
//. Using types as predicates is useful in other contexts too. One could,
//. for example, define a [record type][] for each endpoint of a REST API
//. and validate the bodies of incoming POST requests against these types.
function test(_env, t, x) {
var env = applyParameterizedTypes(_env);
function test(env, t, x) {
var typeInfo = {name: 'name', constraints: {}, types: [t]};
return satisfactoryTypes(env, typeInfo, {}, t, 0, [], [x]).isRight;
}
Expand Down Expand Up @@ -2345,8 +2370,7 @@
throw new RangeError(q(def.name) + ' cannot define a function ' +
'with arity greater than nine');
}
return curry({checkTypes: opts.checkTypes,
env: applyParameterizedTypes(opts.env)},
return curry(opts,
{name: name, constraints: constraints, types: expTypes},
{},
values,
Expand Down Expand Up @@ -2442,33 +2466,25 @@
}));

//. [FL:Semigroup]: https://github.com/fantasyland/fantasy-land#semigroup
//. [`AnyFunction`]: #AnyFunction
//. [`Arguments`]: #Arguments
//. [`Array`]: #Array
//. [`BinaryType`]: #BinaryType
//. [`Boolean`]: #Boolean
//. [`Date`]: #Date
//. [`Error`]: #Error
//. [`FiniteNumber`]: #FiniteNumber
//. [`GlobalRegExp`]: #GlobalRegExp
//. [`Integer`]: #Integer
//. [`NonGlobalRegExp`]: #NonGlobalRegExp
//. [`Null`]: #Null
//. [`Number`]: #Number
//. [`Object`]: #Object
//. [`Object.create`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/create
//. [`Pair`]: #Pair
//. [`RegExp`]: #RegExp
//. [`RegexFlags`]: #RegexFlags
//. [`StrMap`]: #StrMap
//. [`String`]: #String
//. [`SyntaxError`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/SyntaxError
//. [`TypeClass`]: https://github.com/sanctuary-js/sanctuary-type-classes#TypeClass
//. [`TypeError`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypeError
//. [`TypeVariable`]: #TypeVariable
//. [`UnaryType`]: #UnaryType
//. [`UnaryTypeVariable`]: #UnaryTypeVariable
//. [`Undefined`]: #Undefined
//. [`Unknown`]: #Unknown
//. [`ValidNumber`]: #ValidNumber
//. [`env`]: #env
//. [arguments]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/arguments
Expand Down
18 changes: 9 additions & 9 deletions test/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -750,7 +750,7 @@ describe('def', function() {
});

it('reports type error correctly for parameterized types', function() {
var env = $.env.concat([Either, Maybe]);
var env = $.env.concat([Either($.Unknown, $.Unknown), Maybe($.Unknown)]);
var def = $.create({checkTypes: true, env: env});

// a00 :: a -> a -> a
Expand Down Expand Up @@ -1889,7 +1889,7 @@ describe('def', function() {
});

it('supports polymorphism via type variables', function() {
var env = $.env.concat([Either, Maybe, $Pair]);
var env = $.env.concat([Either($.Unknown, $.Unknown), Maybe($.Unknown), $Pair($.Unknown, $.Unknown)]);
var def = $.create({checkTypes: true, env: env});

// aa :: a -> a -> (a, a)
Expand Down Expand Up @@ -2110,7 +2110,7 @@ describe('def', function() {
});

it('supports arbitrary nesting of types', function() {
var env = $.env.concat([Either, $.Integer]);
var env = $.env.concat([Either($.Unknown, $.Unknown), $.Integer]);
var def = $.create({checkTypes: true, env: env});

// unnest :: Array (Array a) -> Array a
Expand Down Expand Up @@ -2218,7 +2218,7 @@ describe('def', function() {
});

it('does not allow heterogeneous arrays', function() {
var env = $.env.concat([Either]);
var env = $.env.concat([Either($.Unknown, $.Unknown)]);
var def = $.create({checkTypes: true, env: env});

// concat :: Array a -> Array a -> Array a
Expand Down Expand Up @@ -2326,7 +2326,7 @@ describe('def', function() {
function(pair) { return [pair[1]]; }
);

var env = $.env.concat([Either, Pair]);
var env = $.env.concat([Either($.Unknown, $.Unknown), Pair($.Unknown, $.Unknown)]);
var def = $.create({checkTypes: true, env: env});

// id :: a -> a
Expand Down Expand Up @@ -2530,7 +2530,7 @@ describe('def', function() {
});

it('supports type-class constraints', function() {
var env = $.env.concat([Integer, Maybe, Either]);
var env = $.env.concat([Integer, Maybe($.Unknown), Either($.Unknown, $.Unknown)]);
var def = $.create({checkTypes: true, env: env});

// Alternative :: TypeClass
Expand Down Expand Up @@ -2735,7 +2735,7 @@ describe('def', function() {
});

it('supports unary type variables', function() {
var env = $.env.concat([Either, Maybe]);
var env = $.env.concat([Either($.Unknown, $.Unknown), Maybe($.Unknown)]);
var def = $.create({checkTypes: true, env: env});

// f :: Type -> Type
Expand Down Expand Up @@ -2811,7 +2811,7 @@ describe('def', function() {
});

it('supports binary type variables', function() {
var env = $.env.concat([$Pair]);
var env = $.env.concat([$Pair($.Unknown, $.Unknown)]);
var def = $.create({checkTypes: true, env: env});

// f :: (Type, Type) -> Type
Expand Down Expand Up @@ -2839,7 +2839,7 @@ describe('def', function() {
function(x) { count += 1; return false; }
);

var env = [$.Array, Maybe, $.Number, Void];
var env = [$.Array($.Unknown), Maybe($.Unknown), $.Number, Void];
var def = $.create({checkTypes: true, env: env});

// head :: Array a -> Maybe a
Expand Down