So... this post here (http://arclanguage.org/item?id=4237) made me realize something: we can combine lists and tables into a single datatype... The left side is pgArc, and the right side is the proposal for Arubic: (obj x 1 y 2) -> (x: 1 y: 2)
((x 1) (y 2)) -> (x: 1 y: 2)
(x 1 y 2) -> (x: 1 y: 2)
But... in addition to offering a nice short syntax for tables, it has further benefits. You can now combine tables and lists: (= foo '(1 2 x: 3 y: 4))
(car foo) -> 1
foo.'x -> 3
Essentially, this is treating it like an "improper" alist. This also blends nicely with keyword arguments: (def foo (a b c)
(list a b c))
(foo c: 3 b: 2 a: 1) -> (1 2 3)
And also with destructuring: (let '(a b c) '(1 c: 3 b: 2)
(list a b c))
-> (1 2 3)
There are still some questions, though... What should the following return? (car '(a: 1))
Should it return (a 1) or nil? Or perhaps the symbol 'a? What about the following? (let '(a b c) '(1 c: 2 3)
(list a b c))
Should it return (1 3 2), (1 2 3), or (1 (c 2) 2)? In other words, are the keywords considered a sequential part of the list, just like an alist, or are they considered a separate and unordered thing, like a hash table?Also, should (a: 1 b: 2) be considered identical to ((a 1) (b 2)), or should it be considered something different, in the same way that alists are different from tables, but serve a similar purpose? Also, should it be (:a 1 :b 2) or (a: 1 b: 2)? I actually kinda like the former... I think I'll go with that. Also also, I dislike the idea of introducing syntax that doesn't desugar into S-expressions... so how will that work with this proposal? Perhaps :a could desugar into (keyword a). That poses problems for destructuring, though: (let '((keyword a) (keyword b)) ...)
(let '(:a :b) ...)
Unless I required nested destructuring to be quoted as well... but that would be freaky: (let '('(keyword a) '(keyword b)) ...)
Or... perhaps keywords shouldn't work with quote destructuring... in which case there's two alternate proposals: (let (keys a b c) foo ...)
(let '(a b c) foo ...)
The nice thing about (keys) is that it's unambiguous and doesn't cause conflicts with destructuring. The downside is that it's a bit longer, and you can't combine list destructuring with table destructuring in a `let` block. You would need to use `with`: (with ((keys a b c) foo
'(d e f) foo)
...)
Which is pretty ugly. The downside of using '(a b c) to destructure keys is that it causes some tricky questions with regard to mixed-type lists, as I already demonstrated above with (1 c: 2 3)Oh, by the way, I can also define `keys` so it works with functions too, so you could specify arguments that must be keyword args: (def foo ((keys a b c))
...)
(foo 1 2 3) ; doesn't work
(foo :a 1 2 3) ; still doesn't work
(foo :a 1 :b 2 :c 3) ; this works
The downside is... then you wouldn't be able to use `apply` to generically call any function. For instance: (def foo ((keys a b)) ...)
(def bar args
(apply foo args))
(bar :a 1 :b 2) ; doesn't work
So maybe I shouldn't do that. Python gets around this by having a special kwargs argument in addition to rest args, but that approach feels pretty "eh" to me. Seems overly complex for not much benefit.Oh, that reminds me. How do you guys think keyword arguments should behave with regard to rest args? In the above example, when calling `bar`, it didn't have an `a` or `b` argument, so what should `args` be? Should it be nil, or should it be (1 2)? |