Trajan
Trajan

Reputation: 370

Pattern matching expressions in Javascript

Im making my way throught functional programming in JS. Recently I started to use Daggy to accomplish simple pattern matching, but I don't think that I fully get it.

Given this code:

  if(a === 1 && !b) {
   do(y)
  }

   if(b === 3 && c === 2) {
    do(z)
  }

  if (a) { 
    do(x) 
  }

Is there a way to improve this cohercions into something similar to?:

   when [a === 1 && !b] : do(y)
   when [a] : do(x)
   when [b === 3 && c === 2]: do(z)

Upvotes: 0

Views: 285

Answers (4)

bas080
bas080

Reputation: 469

Developer and maintainer of Patroon. I was looking for js style pattern matching and had to build my own. This is what your example would look like using the patroon library:

const isNil = x => !(x != null)

patroon(
  {a: 1, b: isNil}, y,
  {b: 3, c: 2}, z,
  {a: _}, x
)({a, b, c})

https://github.com/bas080/patroon

Upvotes: 0

Viktor Pelle
Viktor Pelle

Reputation: 61

Sure with Daggy you could define Maybe

    const Maybe = daggy.taggedSum('Option', {
        Just: ['a'],
        Nothing: []
    })

and then define a prototype function on it called alt which can basically fallback to the passed value

    // alt :: Alt f => f a ~> f a -> f a
    Maybe.prototype.alt = function(o): Maybe<T> {
        return this.cata({
          Just: _ => this,
          Nothing: () => o
        })
      }

So with it we can do some pattern matching or similar

    function match(comparator, res) {
      switch (comparator()) {
        case true: return Maybe.of(res)
        case false: return Maybe.Nothing
        default: return Maybe.Nothing
      }

    }

    MaybeF.Nothing
      .alt(match(() => a === 1 && !b, () => y))
      .alt(match(() => a, () => x))
      .alt(match(() => b === 3 && c === 2, () => z))

Upvotes: 0

David Lemon
David Lemon

Reputation: 1560

You can create a wrapper class to your data and then use functions to check the conditions and do an action in case that the particular condition meets.

Simple and easy, without any libraries.

class typeWrap {

  constructor(obj) {
    this.var  =  obj;
    this.done = false;
  }

  when (condition, doFn) {

    if (!this.done && condition(this.var)) {
      this.done = true;
      doFn(this.var);
    }
    return this;
  }
}

const data = new typeWrap({
  b: 3, c : 9
});

data
  .when(
    d => d.a === 1 && !d.b,
    () => console.log('C1 => y')
  )
  .when(
    d => d.b === 3 && d.c !== 2,
    () => console.log('C2 => z')
  )
  .when(
    d => d.a,
    () => console.log('C3 => x')
  )
  .when(
    d => true,
    () => console.log('Last stop')
  );

Upvotes: 0

T.J. Crowder
T.J. Crowder

Reputation: 1074276

JavaScript doesn't have the kind of pattern matching you're probably talking about. There is an active proposal to add it using case/when, here's an example from that proposal:

const res = await fetch(jsonService)
case (res) {
  when {status: 200, headers: {'Content-Length': s}} -> {
    console.log(`size is ${s}`)
  }
  when {status: 404} -> {
    console.log('JSON not found')
  }
  when {status} if (status >= 400) -> {
    throw new RequestError(res)
  }
}

It's currently just at Stage 1 of the process, though, so it may not proceed, may change radically before proceeding, and may take years to work through the stages and get into the language. There's work on a Babel plugin.

I'm afraid it's not immediately clear to me how I'd apply it to your example, though, as it seems to want an operand for case.

In the meantime, a series of if/else if can be fairly terse if terseness is what you're looking for:

if (a === 1 && !b)           foo(y);
else if (a)                  foo(x);
else if (b === 3 && c === 2) foo(z);

Or JavaScript's switch is unusually flexible (it's really just another way to write if/else if):

switch (true) {
    case a === 1 && !b:      foo(y); break;
    case a:                  foo(x); break;
    case b === 3 && c === 2: foo(z); break;
}

(I'm not advocating it, just pointing out it's an option.)

Upvotes: 3

Related Questions