Open msackman opened 12 years ago
I've thought about some of these things. I've considered some things like that that need parsing, and also considered things like this that need less parsing:
match({ "!a": { value: '\\d', type: 'regex', optional: true } })
It might be worth looking at ClojureScript. I believe they might have gotten both clojure core.match and core.logic running in JS. Also interesting on the ecma script discuss list there has been a discussion on pattern matching just in the last hour (https://mail.mozilla.org/pipermail/es-discuss/2012-April/022395.html)
Interesting stuff. I like the fact the patterns here are structurally isomorphic to the shape of the value being matched against. It's a shame to lose that but if you don't, you end up encoding richer patterns in the text of the match which then starts to introduce a whole sub query language... it gets messy fast. Difficult to know what's best to do.
One other thing I quite fancied trying to add was better nesting so you could do something like:
match({ a: match({foo: 'bar', baz: '$qux'}), b: '$b'}, {a: {foo: bar, baz: 5}, b: 'c'})
but then you really need match
to become some sort of (E)DSL constructor rather than a verb. Or at least provide a suitable DSL constructor.
Your example, what does it buy you? What would that do? match takes two args. The inside match in the example only has one.
I agree having the shape of the code be the same is a good thing. One of the reasons I haven't done anything like this so far.
From what I can guess you are trying to do with the nested match is to bind the whole section to a variable and also bind some of the parts to variables also. So if we had some features like an 'as' keyword we could do the following:
match({ a: { foo: 'bar', baz: '$quz' } as '$a', b: '$b' },
{a: {foo: bar, baz: 5}, b: 'c'})
// { a: { foo: 'bar', baz: '$quz' }, quz: 5, b: 'c' }
Sadly that isn't possible in that form. However if we had a normal function called composeAndMerge
which receives the obj to match against first and an arbitrary number of patterns to match it would match the first pattern then take the bindings object and pass that to the next pattern. If the next one matched it combines merges the two bindings objects together and passes to the next or returns.
composeAndMerge({a: {foo: bar, baz: 5}, b: 'c'}, { a: '$hello' , b: '$b'},
{ hello: {foo: 'bar', baz: '$qux'} })
// { hello: {foo: bar, baz: 5}, qux: 5, b: 'c' }
Yeah, sorry, I overloaded match badly there. I was meaning it more as an ADT constructor in the inner case, saying "the value of a
should match against this thing". I read through the ecma script thread you pointed to - interesting stuff, many thanks. I think use of as
is intuitive provided the language gains full pattern matching and then as
is then just an aliasing technique, a la Haskell or Erlang.
The composeAndMerge
idea is interesting. I can certainly see that working, though the scoping rules would be interesting - you could almost see an RPN style working well!
I like the look of this library a lot and it's very close to meeting my needs. But I'd quite like to see some regexp support:
Currently, the pattern can contain either fully ground values, or variable-placeholders. It would be nice to allow those variable-placeholders to contain regexps sort of maybe in the style of https://github.com/squaremo/rejson
So maybe something like:
would only match if
a
is assigned a number. There are some more interesting open questions though, such as:What do you think? I'm happy to try and hack some of this stuff in myself, but I wonder if you've already had thoughts along these lines?