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

Transformative match clauses #1

Open
ygunayer opened this issue Oct 19, 2019 · 0 comments
Open

Transformative match clauses #1

ygunayer opened this issue Oct 19, 2019 · 0 comments
Labels
enhancement New feature or request

Comments

@ygunayer
Copy link
Owner

Case clauses currently allow only one input and output types, In and Out. By introducing an intermediary type Mid we can allow users to extract information from the initial value in a match clause, and use that intermediate output value in the guard case and the handler function. This would particularly be beneficial in regex patterns. Consider the following example:

Given an input string, we'd like to extract the color and type of a wearable. An implementation of this use case in the current version of the codebase might look like this:

const thing = 'red shirt';
const pattern = () => /(red|green|blue)\s+(shirt|pants|skirt|hat)/g;

match(thing).case(
  [pattern(), str => {
    const [_, color, wearable] = pattern().exec(str);
    console.log(`It's a ${color} ${wearable}`);
  }],
  [_, str => console.log(`Don't know what ${str} is`)]
);

// prints "It's a red shirt"

Notice how the pattern constant is a function that returns the regex pattern, instead of being the pattern instance itself. This is due to the fact that RegExp instances are stateful, and therefore matching it and reusing it later would fail, as in the case below;

const thing = 'red shirt';
const pattern = /(red|green|blue)\s+(shirt|pants|skirt|hat)/g;

match(thing).case(
  [pattern, str => {
    const [_, color, wearable] = pattern.exec(str);
    console.log(`It's a ${color} ${wearable}`);
  }],
  [_, str => console.log(`Don't know what ${str} is`)]
);

// fails with the following error:
//        const [_, color, wearable] = pattern.exec(str);
//                                     ^
// TypeError: object null is not iterable (cannot read property Symbol(Symbol.iterator))

Likewise, implementing guard cases against regex matches are so cumbersome that it's impractical:

const thing = 'yellow submarine';
const pattern = () => /(red|green|blue|yellow)\s+(shirt|pants|skirt|hat|submarine)/g;

match(thing).case(
  [
    pattern(),
    str => {
      const [_, color, wearable] = pattern().exec(str);
      return color == 'yellow' && wearable == 'submarine';
    },
    str => {
      const [_, color, wearable] = pattern().exec(str);
      console.log(`We all live in a ${color} ${wearable}, ${color} ${wearable}, ${color} ${wearable}`);
    }
  ],
  [pattern(), str => {
    const [_, color, wearable] = pattern().exec(str);
    console.log(`It's a ${color} ${wearable}`);
  }],
  [_, str => console.log(`Don't know what ${str} is`)]
);

// prints "We all live in a yellow submarine, yellow submarine, yellow submarine"

If transformative match clauses were to be implemented, we'd expect the examples above to be boiled down to the following:

const thing = 'red shirt';
const pattern = /(red|green|blue)\s+(shirt|pants|skirt|hat)/g;

match(thing).case(
  [pattern, ([_, color, wearable]) => console.log(`It's a ${color} ${wearable}`)],
  [_, str => console.log(`Don't know what ${str} is`)]
);

// prints "It's a red shirt"
import {_, match} from '..';

const thing = 'yellow submarine';
const pattern = () => /(red|green|blue|yellow)\s+(shirt|pants|skirt|hat|submarine)/g;

match(thing).case(
  [pattern(), [_, 'yellow', 'submarine'], ([_, color, wearable]) => console.log(`We all live in a ${color} ${wearable}, ${color} ${wearable}, ${color} ${wearable}`)],
  [pattern(), ([_, color, wearable]) => console.log(`It's a ${color} ${wearable}`)],
  [_, str => console.log(`Don't know what ${str} is`)]
);

// prints "We all live in a yellow submarine, yellow submarine, yellow submarine"

Note: We had to reuse the same pattern in two matching match clauses, so we converted it back into a function

@ygunayer ygunayer added the enhancement New feature or request label Oct 19, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

1 participant