Skip to content

Commit

Permalink
Merge pull request #182 from sanctuary-js/davidchambers/types
Browse files Browse the repository at this point in the history
types: rename Pair type constructor and define Array0 and Array1
  • Loading branch information
davidchambers authored Mar 29, 2018
2 parents d0e5084 + acd6cc2 commit 1761137
Show file tree
Hide file tree
Showing 2 changed files with 102 additions and 64 deletions.
48 changes: 34 additions & 14 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -473,6 +473,34 @@
//. Constructor for homogeneous Array types.
var Array_ = UnaryTypeWithUrl('Array', typeEq('Array'), id);

//# Array0 :: Type
//.
//. Type whose sole member is `[]`.
var Array0 = NullaryTypeWithUrl(
'sanctuary-def/Array0',
function(x) { return typeEq('Array')(x) && x.length === 0; }
);

//# Array1 :: Type -> Type
//.
//. Constructor for singleton Array types.
var Array1 = UnaryTypeWithUrl(
'sanctuary-def/Array1',
function(x) { return typeEq('Array')(x) && x.length === 1; },
id
);

//# Array2 :: Type -> Type -> Type
//.
//. Constructor for heterogeneous Array types of length 2. `['foo', true]` is
//. a member of `Array2 String Boolean`.
var Array2 = BinaryTypeWithUrl(
'sanctuary-def/Array2',
function(x) { return typeEq('Array')(x) && x.length === 2; },
function(array2) { return [array2[0]]; },
function(array2) { return [array2[1]]; }
);

//# Boolean :: Type
//.
//. Type comprising `true` and `false`.
Expand Down Expand Up @@ -676,17 +704,6 @@
//. constructor function.
var Object_ = NullaryTypeWithUrl('Object', typeEq('Object'));

//# Pair :: Type -> Type -> Type
//.
//. Constructor for tuple types of length 2. Arrays are said to represent
//. tuples. `['foo', 42]` is a member of `Pair String Number`.
var Pair = BinaryTypeWithUrl(
'sanctuary-def/Pair',
function(x) { return typeEq('Array')(x) && x.length === 2; },
function(pair) { return [pair[0]]; },
function(pair) { return [pair[1]]; }
);

//# PositiveFiniteNumber :: Type
//.
//. Type comprising every [`FiniteNumber`][] value greater than zero.
Expand Down Expand Up @@ -1489,7 +1506,8 @@

//# BinaryType :: String -> String -> (Any -> Boolean) -> (t a b -> Array a) -> (t a b -> Array b) -> (Type -> Type -> Type)
//.
//. Type constructor for types with two type variables (such as [`Pair`][]).
//. Type constructor for types with two type variables (such as
//. [`Array2`][]).
//.
//. To define a binary type `t a b` one must provide:
//.
Expand Down Expand Up @@ -2574,6 +2592,9 @@
AnyFunction: AnyFunction,
Arguments: Arguments,
Array: fromUncheckedUnaryType(Array_),
Array0: Array0,
Array1: fromUncheckedUnaryType(Array1),
Array2: fromUncheckedBinaryType(Array2),
Boolean: Boolean_,
Date: Date_,
Error: Error_,
Expand All @@ -2594,7 +2615,6 @@
Nullable: fromUncheckedUnaryType(Nullable),
Number: Number_,
Object: Object_,
Pair: fromUncheckedBinaryType(Pair),
PositiveFiniteNumber: PositiveFiniteNumber,
PositiveInteger: PositiveInteger,
PositiveNumber: PositiveNumber,
Expand Down Expand Up @@ -2630,6 +2650,7 @@
//. [Monoid]: https://github.com/fantasyland/fantasy-land#monoid
//. [Setoid]: https://github.com/fantasyland/fantasy-land#setoid
//. [`Array`]: #Array
//. [`Array2`]: #Array2
//. [`BinaryType`]: #BinaryType
//. [`Date`]: #Date
//. [`FiniteNumber`]: #FiniteNumber
Expand All @@ -2638,7 +2659,6 @@
//. [`NonGlobalRegExp`]: #NonGlobalRegExp
//. [`Number`]: #Number
//. [`Object.create`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/create
//. [`Pair`]: #Pair
//. [`RegExp`]: #RegExp
//. [`RegexFlags`]: #RegexFlags
//. [`String`]: #String
Expand Down
118 changes: 68 additions & 50 deletions test/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -1652,6 +1652,67 @@ Since there is no type of which all the above values are members, the type-varia
eq($.Array(a).url, `https://github.com/sanctuary-js/sanctuary-def/tree/v${version}#Array`);
});

test('provides the "Array0" type', () => {
eq($.Array0.name, 'sanctuary-def/Array0');
eq($.Array0.url, `https://github.com/sanctuary-js/sanctuary-def/tree/v${version}#Array0`);

const isEmptyArray = $.test($.env, $.Array0);
eq(isEmptyArray(null), false);
eq(isEmptyArray([]), true);
eq(isEmptyArray([0]), false);
});

test('provides the "Array1" type constructor', () => {
eq(typeof $.Array1, 'function');
eq($.Array1.length, 1);
eq($.Array1.toString(), 'Array1 :: Type -> Type');
eq($.Array1(a).name, 'sanctuary-def/Array1');
eq($.Array1(a).url, `https://github.com/sanctuary-js/sanctuary-def/tree/v${version}#Array1`);
eq($.Array1(a).toString(), '(Array1 a)');

const isSingletonStringArray = $.test($.env, $.Array1($.String));
eq(isSingletonStringArray(null), false);
eq(isSingletonStringArray([]), false);
eq(isSingletonStringArray([0]), false);
eq(isSingletonStringArray(['x']), true);
eq(isSingletonStringArray(['x', 'y']), false);
});

test('provides the "Array2" type constructor', () => {
eq(typeof $.Array2, 'function');
eq($.Array2.length, 2);
eq($.Array2.toString(), 'Array2 :: Type -> Type -> Type');
eq($.Array2(a, b).name, 'sanctuary-def/Array2');
eq($.Array2(a, b).url, `https://github.com/sanctuary-js/sanctuary-def/tree/v${version}#Array2`);
eq($.Array2(a, b).toString(), '(Array2 a b)');
eq($.Array2(a)(b).toString(), '(Array2 a b)');

// fst :: Array2 a b -> a
const fst = def('fst', {}, [$.Array2(a, b), a], array2 => array2[0]);

// snd :: Array2 a b -> b
const snd = def('snd', {}, [$.Array2(a, b), b], array2 => array2[1]);

eq(fst(['foo', 42]), 'foo');
eq(snd(['foo', 42]), 42);

throws(
() => fst(['foo']),
TypeError,
`Invalid value
fst :: Array2 a b -> a
^^^^^^^^^^
1
1) ["foo"] :: Array String
The value at position 1 is not a member of ‘Array2 a b’.
See https://github.com/sanctuary-js/sanctuary-def/tree/v${version}#Array2 for information about the sanctuary-def/Array2 type.
`);
});

test('provides the "Boolean" type', () => {
eq($.Boolean.name, 'Boolean');
eq($.Boolean.url, `https://github.com/sanctuary-js/sanctuary-def/tree/v${version}#Boolean`);
Expand Down Expand Up @@ -2113,49 +2174,6 @@ Since there is no type of which all the above values are members, the type-varia
`);
});

test('provides the "Pair" type constructor', () => {
eq(typeof $.Pair, 'function');
eq($.Pair.length, 2);
eq($.Pair.toString(), 'Pair :: Type -> Type -> Type');
eq($.Pair(a, b).name, 'sanctuary-def/Pair');
eq($.Pair(a, b).url, `https://github.com/sanctuary-js/sanctuary-def/tree/v${version}#Pair`);
eq($.Pair(a, b).toString(), '(Pair a b)');
eq($.Pair(a)(b).toString(), '(Pair a b)');

// fst :: Pair a b -> a
const fst =
def('fst',
{},
[$.Pair(a, b), a],
pair => pair[0]);

// snd :: Pair a b -> b
const snd =
def('snd',
{},
[$.Pair(a, b), b],
pair => pair[1]);

eq(fst(['foo', 42]), 'foo');
eq(snd(['foo', 42]), 42);

throws(
() => fst(['foo']),
TypeError,
`Invalid value
fst :: Pair a b -> a
^^^^^^^^
1
1) ["foo"] :: Array String
The value at position 1 is not a member of ‘Pair a b’.
See https://github.com/sanctuary-js/sanctuary-def/tree/v${version}#Pair for information about the sanctuary-def/Pair type.
`);
});

test('uses Z.toString-like string representations', () => {
// f :: Null -> Null
const f =
Expand Down Expand Up @@ -2874,11 +2892,11 @@ reduce_ :: ((a, b) -> a) -> a -> Array b -> a
The value at position 1 is not a member of ‘(a, b) -> a’.
`);

// unfoldr :: (b -> Maybe (Pair a b)) -> b -> Array a
// unfoldr :: (b -> Maybe (Array2 a b)) -> b -> Array a
const unfoldr =
def('unfoldr',
{},
[$.Function([b, Maybe($.Pair(a, b))]), b, $.Array(a)],
[$.Function([b, Maybe($.Array2(a, b))]), b, $.Array(a)],
(f, x) => {
const result = [];
for (let m = f(x); m.isJust; m = f(m.value[1])) {
Expand All @@ -2887,7 +2905,7 @@ The value at position 1 is not a member of ‘(a, b) -> a’.
return result;
});

// h :: Integer -> Maybe (Pair Integer Integer)
// h :: Integer -> Maybe (Array2 Integer Integer)
const h = n => n >= 5 ? Nothing : Just([n, n + 1]);

eq(unfoldr(h, 5), []);
Expand All @@ -2899,13 +2917,13 @@ The value at position 1 is not a member of ‘(a, b) -> a’.
TypeError,
`Invalid value
unfoldr :: (b -> Maybe (Pair a b)) -> b -> Array a
^^^^^^^^^^^^^^^^^^^^^^^
1
unfoldr :: (b -> Maybe (Array2 a b)) -> b -> Array a
^^^^^^^^^^^^^^^^^^^^^^^^^
1
1) null :: Null
The value at position 1 is not a member of ‘b -> Maybe (Pair a b)’.
The value at position 1 is not a member of ‘b -> Maybe (Array2 a b)’.
`);

// T :: a -> (a -> b) -> b
Expand Down

0 comments on commit 1761137

Please sign in to comment.