Will the empty list be false-y? I kinda like that it is.
Both these ideas help make programs terser in Arc. Here's a definition that uses both:
(def map1 (f xs)
"Returns a list containing the result of function 'f' applied to every element of 'xs'."
(if xs
(cons (f car.xs)
(map1 f cdr.xs))))
I like keyword arguments too, but I don't follow what your preceding proposals have to do with it.You know what language has perfect interop with Racket? Racket ^_^
(define (xcdr x)
(if (pair? x) (cdr x) ar-nil))
and ar-nil is falsy. So your example will work unmodified.... oh. And now that I check, you're right about void:
arc> (seval '(if (void) 1 2))
1
I foolishly assumed that (void) in racket is falsy. But it's truthy. That rules out using racket's (void). `(null ? 1 : 2)` gives 2 in JS, and `if nil then 1 else 2 end` gives 2 in Lua, so it's surprising that `(if (void) 1 2)` gives 1 in Racket.For what it's worth, in an experimental version, using #f for ar-nil and #t for ar-t worked. It's a bit of a strange idea, but it helps interop significantly due to being able to pass arc predicates right into racket.
It'd be better for me to show a working prototype with ar-nil set to #f rather than try to argue in favor of it here. But to your original question: yes, anything other than |nil| would be great, since that gets rid of the majority of interop headaches.
One thing that might be worth pointing out: The lack of void means it's back to the old question of "how do you express {"a": false, "b": []} in arc?" Choosing between #f and () for nil implies a choice between forcing {"a": false} or {"b": []} to be the only possible hash table structures, since one of them would be excluded from hash tables. But that might be a tangent.
Yes, the keyword section was poorly explained. My comment should have been prefixed with "some thoughts on arc, in case it's helpful" rather than "here is a proposal." And then I should have taken that comment and put it in a different thread, since keyword arguments are unrelated to the question of nil becoming (). I was mostly just excited for the possibility of leveraging more racket now that denil/niltree might be cut soon.
-----
Would disambiguation here really make Arc programs less terse? Is that a decision that should be enforced by the language or left to the author?
-----
(def map1 (f xs)
"Returns a list containing the result of function 'f' applied to every element of 'xs'."
- (if xs
+ (if (~empty? xs)
(cons (f car.xs)
(map1 f cdr.xs))))
We can argue how important this is, but disambiguation does definitely make Arc programs less terse.-----
- the assumption baked into this argument is that cdr of an empty list returns an empty list. Switching nil to #f and letting empty list be truthy avoids this problem.
- Good names are important. ~empty? isn't really a fair characterization. Lumen uses (some? xs). There is also another way: Update `no` to be (or (is x nil) (empty x)), and then use (~no xs).
-----
Second option, part a: I actually find `~empty?` clearer than `some` in this case. Also `some` means something different in Arc.
Second option, part b: wait, then `(if xs ...)` would sometimes not do the opposite of `(if (no xs) ...)`!
-----
(expect subject pattern else
then)
->
(match subject
[pattern then]
[_ else])
If Arc came with a similar pattern-matching DSL and `expect`, we could write this: (def map1 (f xs)
(expect xs (cons x xs) ()
(cons (f x) (map1 f xs))))
The line "expect xs (cons x xs) ()" conveys "If xs isn't a cons cell, finish with an empty list. Otherwise, proceed with x and xs bound to its car and cdr."-----
I read a good blog post[0] recently on how not distinguishing makes it difficult to guess the behaviour of simple and short code snippets (in JavaScript, but the same could apply to Arc).
[0]: https://medium.com/@winwardo/the-principle-of-least-astonish...
-----
-----