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

Add pattern matching #4

Open
Gozala opened this issue Aug 19, 2015 · 1 comment
Open

Add pattern matching #4

Gozala opened this issue Aug 19, 2015 · 1 comment

Comments

@Gozala
Copy link
Collaborator

Gozala commented Aug 19, 2015

Currently used patten in most code is something along these lines:

const Model = Record({value: Number})

const Increment = Record({label: '+'});
const Decrement = Record({label: '-'});
const Action = Union(Increment, Decrement);

const update = (model, action) =>
  action instanceof Increment ? model.update('value', x => x + 1) :
  action instanceof Decrement ? model.update('value', x => x - 1) :
  model;

With a pattern matching it should be possible to turn it to something like this:

const update = Match(Match._, Match.pattern)
  .case(Increment, (model, _) => model.update('value', x => x + 1))
  .case(Decrement, (model, _) => model.update('value', x => x + 1))
  .default((model, _) => model)
@Gozala
Copy link
Collaborator Author

Gozala commented Aug 19, 2015

Here is a very basic implementation:

function Match(...params) {
  if (this instanceof Match) {
    this.fallback = null
    this.rules = []
    this.index = Match.max(0, params.indexOf(Match.pattern))
  } else {
    return new Match(...params)
  }
}
Match.prototype.case = function(type, clause) {
  if (this.fallback) {
    throw TypeError('Match already has a default clause')
  }
  this.rules.push({type, clause})
  return this
}
Match.prototype.default = function(clause) {
  if (this.fallback) {
    throw TypeError('Match already has a default clause')
  }

  this.fallback = clause
  return this.compile()
}
Match.prototype.compile = function() {
  if (!this.fallback) {
    throw TypeError('Can not compile matcher that has no default case')
  }

  const {rules, index, fallback} = this
  return (...params) => {
    const pattern = params[index]
    for (let {type, clause} of rules) {
      if (type.isTypeOf(pattern)) {
        return clause(...params)
      }
    }
    return fallback(...params)
  }
}
Match.pattern = new String('Match.pattern')
Match._ = new String('Match._')

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant