LiveScript
LiveScript copied to clipboard
Pseudo pattern matching
It'd be cool if we had a match statement, which ran its operand against the functions in its cases. For example:
console.log match x
| is-NaN => "not a number"
| is-finite => "not infinity"
| otherwise => "something else"
Cool.
console.log match x
| (instanceof SomeClass) => "SomeClass"
| (instanceof AnotherClass) => "AnotherClass"
| otherwise => "something else"
:+1: very good idea
+1 on that
And we can add something more sophisticated to it when there will be static type checking
http://kerflyn.wordpress.com/2011/02/14/playing-with-scalas-pattern-matching/
console.log match x,
is-NaN => "not a number"
is-finite => "not infinity"
otherwise => "something else"
where:
match = (x, ...cases) ->
for c, i in cases by 2
return cases[i+1] if c x
cases[i-1]
otherwise = -> true
@satyr if the results have side effects, that won't work
if the results have side effects, that won't work
It should accept functions as results for a real implementation. Makes for a good prelude addition I guess.
If it does get done, this would be a good use for pure function annotations
I added some more features. You can use it with no subject at all, or multiple arguments.
# no subject
false-func = -> false
true-func = -> true
match
| false-func => ok 0
| true-func => ok 1
| otherwise => ok 0
# multiple arguments
x = 1
y = 2
match x, y
| (==) => ok 0
| (>) => ok 0
| (<) => ok 1
| _ => ok 0
Dude, that's awesome. Any ETA on 0.9.13/0.10?
Some time in the next week.
imo it should work when var defs are located after newline after where too
quick-sort = ([x, ...xs]:list) ->
| empty list => []
| otherwise => (quick-sort left) +++ [x] +++ (quick-sort right) where
[right, left] = partition (<= x), xs
All hail our new match statement overlords!
take = (n, [x, ...xs]:list) -->
match n, list
| (<= 0), _ => []
| _ , [] => []
| otherwise => [x] +++ take n - 1, xs
take 3, [1 to 10] #=> [1, 2, 3]
also
match 1, 2
| odd, odd => ok 0
| even, even => ok 0
| odd, even => ok 1
| otherwise => ok 0
also
x = [1 2 3]
y = 'haha'
z = {+foo, moo: 2, g: {hi: \?}}
match x, y, z
| [1 2 3], /^ha/g, {foo: true, moo: 2, g: {hi: \!}} => ok 0
| [1 2 3], /^ha/g, {foo: true, moo: 2, g: {hi: \?}} => ok 1
| otherwise => ok 0
etc.
@gkz how about making this a main matching syntax in function declarations instead of current switch?
take = (n, [x, ...xs]:list) -->
| (<= 0), _ => []
| _, [] => []
| otherwise => [x] +++ take n - 1, xs
@paulmillr: + a lot
I was thinking about that too. I think I'll need to think more about the consequences of it before going ahead.
Changes I made to make the above possible - feel free to discuss
- added deep equal, based off of underscore.js's
isEqual, to compare objects and arrays. eg.a === b,a <== b,a <<= betc. adds a huge ass util func ==when one of the operands is a regex literal does.exec, (allowing use ofthatfor results),!=compiles to.test- binary logic is callable, eg.
(f or g) xis equal to(f x or g x)- also does deepEq or other stuff as necessary - added
xoroperator, ie exclusiveor, is true when one but not the other operand is true, evaluates to the one that is true - and more stuff check the last ~16 commits
Woah, woah, woah. A little harsh for me !
take = (n, [x, ...xs]:list) -->
match n, list
| (<= 0), _ => []
| _ , [] => []
| otherwise => [x] +++ take n - 1, xs
take 3, [1 to 10] #=> [1, 2, 3]
Really took me quite time to understand that "_" are used here to say "whatever for this value"
match 1, 2
| odd, odd => ok 0
| even, even => ok 0
| odd, even => ok 1
| otherwise => ok 0
erm ... does the following still works ?
sortBy = (prop, list) -->
list.sort (a, b) -> match a[prop], b[prop]
| (<) => -1
| (>) => 1
| otherwise => 0
No, the multiple arguments thing was dropped instead for multiple simultaneous checks.
not sure I completely agree with that. I think I prefer to write nested switch, because the reading of the match / the cases becomes too messy really easily. I'll have to look "ok, so the comma is here, the 4 is to test against the b, and ..." -1 for this, especially with the implicit functions
I don't think I'll make match the default because match is not as stable (may change in the future), is more complex, and has a messier compilation.
Isn't it possible to add back the "multiple arguments" when match arglist's length > case arglist's length, allowing the following possible
match iA, iB
| (==) => "Equal int"
| (>) => "A gt B"
| odd, even => "a odd and b even"
The rule would be simple : if we have a/some missing case(s), then it's/they're argument(s) for the prev case. I.e. :
match a, b, c
| test => 'called test(a, b, c)'
| test, tryndie => 'called test(a) and tryndie(b, c)'
| foo, _, _ => 'called foo(a)'
I don't know if that'd be possible without creating some slow/ugly, but I think that'd bring the best of both worlds.
Talking about #123 (yay nice number), would you consider moving this to "switch" ?
x = [1 2 3]
y = 'haha'
z = {+foo, moo: 2, g: {hi: \?}}
switch x, y, z
| [1 2 3], /^ha/g, {foo: true, moo: 2, g: {hi: \!}} => ok 0
| [1 2 3], /^ha/g, {foo: true, moo: 2, g: {hi: \?}} => ok 1
| otherwise => ok 0
Since it isn't a call in any way
Possible ideas to rip off https://github.com/natefaubion/matches.js
currently, match a, b case foo => 1 will call foo([a, b]). Is it working as intended ? shouldn't it be foo(a, b) ?
george would be possible do destructuring with pattern matching n=[1,2,3,4] match n, list | [a,,,b] => "first is #a last is #b long: 4" | otherwise => "this is not an useful pattern matching..."
Except match n.0, n.1, n.2, n.3 I don't see how that'd work anyway
"this is not an useful pattern matching..."
Oh yeah, totally not. right.
How to check typeof?
a = "abc"
match a
| (typeof a is "string") => 1 #doesn’t work
| _ => 2
(typeof) >> (is "string"), or simply (-> typeof it is "string")
in the new prelude.ls we have is-type
http://preludels.com/#is-type
Is there possibility to check another types, like function, date, regexp, element etc?