Closed fosskers closed 1 year ago
Hi! Yes. this is by design, though it is not described anywhere. Should be added to the reference.
It's mentioned in the reference:
Tables will never fail to match due to having too many elements - this means
[]
matches any table, not an empty table.
Maybe we could make it clearer tho; I don't know. Open to suggestions.
This is consistent with the way that argument checking works on lambda
: we ensure that all the given locals have a value, but there are no checks to see whether too many args were passed in.
Thanks guys, this is clearer now. This also brought case
to my attention, so that's good.
there are no checks to see whether too many args were passed in.
And also too few, it looks like:
(match [1 2 3]
[1 2 3 _ _] "something"
[] "empty"
_ "else")
Returns "something"
, but:
(match [1 2 3]
[1 2 3 4 _] "something"
[] "empty"
_ "else")
Returns "empty"
. I'm not (as) surprised by the latter, but am certainly by the former. For the former we see some cute Lua:
if ((_G.type(_1_) == "table") and ((_1_)[1] == 1) and ((_1_)[2] == 2) and ((_1_)[3] == 3) and true and true) then
re: the and true and true
. What's reasonable to expect in this case?
The first one matches because _
means "always match no matter what"; this is a common idiom across most languages that have pattern matching. Similarly any symbol starting with a question mark is allowed to be nil. But any other symbol will prevent it from matching:
(match [1 2 3]
[1 2 3 x _] "at-least-4"
[] "maybe-empty"
_ "else")
Thanks! I'll keep these semantics in mind.
For completeness sake:
Haskell
-- outputs "else"
test = case [1,2,3] of
1:2:3:_:_ -> "something"
[] -> "empty"
_ -> "else"
-- outputs "something"
test = case [1,2,3] of
1:2:3:_ -> "something"
[] -> "empty"
_ -> "else"
Rust (notice the syntactic difference between "there is a slot here and I don't care what it is" vs "I don't care what comes after this")
// outputs "else"
fn test() -> &'static str {
match vec![1, 2, 3].as_slice() {
[1, 2, 3, _, _] => "something",
[] => "empty",
_ => "else",
}
}
// outputs "something"
fn test() -> &'static str {
match vec![1, 2, 3].as_slice() {
[1, 2, 3, ..] => "something",
[] => "empty",
_ => "else",
}
}
Emacs Lisp
;; outputs 'something
(pcase '(1 2 3)
((seq 1 2 3 _ _) 'something)
('() 'empty)
(_ 'else))
;; outputs 'something
(pcase '(1 2 3 4 5 6)
((seq 1 2 3 _ _) 'something)
('() 'empty)
(_ 'else))
;; outputs 'else
(pcase '(1 2 3)
('(1 2 3 _ _) 'something)
('() 'empty)
(_ 'else))
Common Lisp
(ql:quickload :trivia)
;; outputs 'else
(trivia:match '(1 2 3)
((list 1 2 3 _ _) 'something)
('() 'empty)
(_ 'else))
Elixir (similar to Rust, we see a syntactic difference between ignoring individual slots vs. the rest)
# outputs "else"
case [1, 2, 3] do
[1, 2, 3, _, _] -> "something"
[] -> "empty"
_ -> "else"
end
# outputs "something"
case [1, 2, 3] do
[1, 2, 3 | _] -> "something"
[] -> "empty"
_ -> "else"
end
So in general, it seems like pcase
in Emacs Lisp resembles Fennel's behaviour, but other languages often have a way to distinguish between an ignored single slot and an ignored "rest".
There's one thing all your languages listed have in common with each other but not with Fennel: in all of them, calling a function with more arguments than it is declared is an error. In Fennel, the additional arguments are ignored.
So Fennel's match
behavior is consistent with its function calling behavior. The one that's inconsistent is Emacs Lisp.
Roger, thanks. The take-home for me (and future readers) is thus:
So Fennel's match behavior is consistent with its function calling behavior.
Hi! Thanks again for Fennel.
I ran into a surprising match result today. Given:
This results in:
The underlying Lua is:
So we see here that in the first branch, only the type is checked and not the shape of the innards. So even though our table is larger than the given pattern, this match-branch succeeds. I found this result surprising relative to the match semantics of other languages, but is this by design? (I'd honestly expect the second branch to fail too, but we can see from the Lua that it too would pass if given the chance.)
Cheers!