Product and terminal contracts

In the last post, we saw a function from nat32 to str:

var spaces = function (n) {
  nat32(n);
  var result = new Array(n + 1).join(' ');
  return str(result);
};

This function is pretty specific: it only gives repetitions of the space character. What if we wanted to have lines of hyphens or asterisks or my name? We could write

var repeat = function (s, n) {
  str(s); nat32(n);
  var result = (new Array(n + 1)).join(s);
  return str(result);
};

and then say repeat('.oOo', 6) to get a nice scalloped edge: .oOo.oOo.oOo.oOo.oOo.oOo

If the type signature of spaces is spaces:nat32 -> str, what is the type signature of repeat? We have two contracts being applied, not just one. If we want to stick to the rule that we have one contract for input and one for output, we have to combine them somehow. Here, we want a function that will take a list of contracts and produce a single contract that we can apply to the list of arguments:

var arr = function (a) {
  if (!Array.isArray(a)) {
    throw new TypeError('Expected an array.');
  }
  return a;
};

// Takes an array-like object---one with a
// length property and numeric properties---
// and returns an actual array instance.
// This is necessary because the 'arguments'
// object only duck types as an array.
var toArray = function (a) {
  var result = [];
  for (var i = 0; i < a.length; ++i) {
    result[i] = a[i];
  }
  return arr(result);
};

var makeProduct = function (cs) {
  arr(cs);
  var len = cs.length;
  return function (args) {
    arr(args);
    if (args.length !== len) {
      throw new TypeError('Expected ' +
          len + ' arguments');
    }
    for (var i = 0; i < len; ++i) {
      // Apply each contract to the
      // corresponding argument.
      cs[i](args[i]);
    }
    return args;
  };
};

var str_x_nat32 = makeProduct([str, nat32]);

var repeat = function (s, n) {
  str_x_nat32(toArray(arguments));
  var result = (new Array(n + 1)).join(s);
  return str(result);
};

Now we can say repeat: str_x_nat32 -> str. I chose to use _x_ in the name to remind us that the set of values that pass this new contract is the cartesian product of the sets that pass str and nat32, respectively.

What about the empty list of contracts?

var terminal = makeProduct([]);

The name ‘terminal’ means that there’s a unique function from any contract c to terminal; the only acceptable output value is an empty array, so it just throws away its input.

var makeUnique = function (c) {
  return function (x) {
    c(x);
    return terminal([]);
  };
};
Advertisements

2 Comments to “Product and terminal contracts”

  1. Shouldn’t the line following the definition of makeProduct be:

    var str_x_nat32 = makeProduct([str, nat32]);

    ?

Leave a Reply

Please log in using one of these methods to post your comment:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: