Closed Renegatto closed 1 year ago
If you want to match on multiple values. you need to use multiple value binding syntax:
(macro vararg-macro [...]
(case ...
(a b) b
x x))
(vararg-macro 1 2) ;=> 2
In case of your macro it didn't match because you didn't provide a table.
I'm curious why it matches in the second case, but I assume that `(,...) somehow was interpreted as a list, which can be matched with the sequential table.
@andreyorst also why ...
is interpreted as 1
instead of {1 2}
and (type ...)
as "number"
instead of "table"
?
It seems like a bug that we can pattern-match on number and successfully match table.
I think you are misunderstanding how ...
works. ...
evaluates as (values 1 2)
, not 1
nor [1 2]
. (type ...)
expands to (type 1 2)
, and since type only reads its first argument, it evaluates to number
.
When you quote and unquote it, you are also wrapping it in a list, which is why you see the change in your code's behavior.
`(,...)
;; is the same as
(list ...)
You can use []
patterns to destructure lists and tables, but you need to use ()
patterns to match multiple values.
...
works the same way outside of macros, and inherits its behavior from lua:
local function example_fn(...)
print(...) -- => 1 2
print(type(...)) -- => number
local x = ...
print(x) -- => 1
local args = {...} -- => {1, 2}
end
example_fn(1, 2)
This is one of the most confusing things about Fennel; unfortunately we can't do much about it since we're stuck with this from Lua.
However, there's really no reason to ever use ...
in macros. You seem to be assuming it works like a table, but if what you want is a table, you can get a table using &
:
(macro vararg-macro [& args]
(case args
[a b] b
x x))
Perhaps we should update our documentation to prefer this style since it's so much less confusing.
I've updated the docs to use the nicer style for rest args: https://git.sr.ht/~technomancy/fennel/commit/7d5d8fa575ca087ebfd16b2d19291df2feb811aa
I think we can close this out but feel free to ask if anything else isn't clear.
In this case
...
is treated as1
i.e.number
However, the code begins to work after quote and unqote: