Skip to content

eborden/JS-Pattern-Matching

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

8 Commits
 
 

Repository files navigation

Destructuring is one of the most powerful features of ES6. It allows for painless assignment of variables, but it could be so much more.

Destructuring is pattern matching. You can see this in one of the most shopped around examples of destructuring, flipping context.

var a = 1,
    b = 2;
console.log([b, a] = [a, b]);

Inherently this operation is matching a pattern.

In spyder monkey (one of the few engines supporting destructuring) it returns the matched array. This can be a useful tool.

Consider the following statement:

if (i = true) {
  console.log('this passes');
}

The implicit value is obvious in left hand assignment. It is the value of i. With a destructured statement the value is less implicit, but logical to infer.

console.log([a, b] = [1, 2]);// [1, 2]
console.log([a, b] = [1]);// [1]

Now consider the following:

([a, b] = [1, 2]).length;// true, all values have been fufilled
([a, b] = [1]).length == 2;// false, all values have not been fufilled

Rest parameters get a bit more complicated, since a rest parameter will return an empty array when no value is present:

console.log([a, ...rest] = [1, 2]);// [1, [2]]
console.log([a, ...rest] = [1]);// [1, []]

Sadly length fails to provide any significant test of pattern fufillment. length again fails in the case of arrays with undefined values.

var x = [];
x[0] = 1;
x[2] = 3;
([a, b, c] = x).length;// 3

With this in mind a testing operator needs to be implemented, so we can get the full power of pattern matching. I propose the ?= operator as an existential pattern matcher.

[a, b] ?= [1, 2];// true
[a, b] ?= [1];// false
[a, ...rest] ?= [1, 2];// true
[a, ...rest] = [1];// false
var x = [];
x[0] = 1;
x[2] = 3;
[a, b, c] ?= x;// false

?= providing let style assignment would further its usefulness.

if ([x, ...rest] ?= [1, 2, 3, 4]) {
  console.log(rest);
}

In this context rest parameters could be expanded to include an unassigned rest.

[a, ...] ?= [1, 2];// true
[a, ...] ?= [1];// false

With destructured pattern matching (and tail call optimization) we could implement elegant recursive functions.

function reverse (a) {
  if (a.length < 1) {
     return [];
  } else if ([x, ...rest] ?= a) {
     return reverse(rest).concat(x);
  }
}

I have excluded the use of object destructuring for simplicity, but the concept easily transfers:

if ({parent: {child: {name: n}}} ?= obj) {
  console.log('child has a name');
}

About

A case study on destructuring and pattern matching.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published