; definition of falseness for Arc if.
; must include '() since sometimes Arc functions see
; Scheme lists (e.g. . body of a macro).
So '() is ar-false? to interact nicely with Scheme. Notice #f is ar-false?, too.
I don't think there's much to it: pg just seems to prefer to spell the empty list nil instead of (). The only place I can think of where these different spellings are useful is in argument lists. That is, I prefer
(def f () something)
to
(def f nil something)
Otherwise, I'm used to nil, though I'd probably get used to () just as well.
The ;XXX in ac marks code that special-cases nil so as previous uses don't break -- i.e., so I didn't have to change every nil to 'nil in arc.arc et al. For example, the literal nils in map1 and so forth:
arc> (map1 [+ _ 1] (list 1 2 3))
(2 3 4)
arc> (if nil 'a 'b)
b
arc> (if 'nil 'a 'b)
b
arc> (= nil 'blah-blah-i-am-true-blah)
blah-blah-i-am-true-blah
arc> (map1 [+ _ 1] (list 1 2 3)) ; literal nil still treated like empty list
(2 3 4)
arc> (if nil 'a 'b)
a
arc> (if 'nil 'a 'b)
b
More importantly, do you actually have a reason you want to rebind the canonical false value? I mean, basically all it could do is break. At least t is only boolean true because it's a symbol other than 'nil. Even with the special case above, you have macro issues:
arc> (if (or (> 1 2) (> 3 4)) 'a 'b)
b
arc> (= nil "At a certain point, this just gets silly...")
"At a certain point, this just gets silly..."
arc> (if (or (> 1 2) (> 3 4)) 'a 'b)
a
Unless you gut Arc to use 'nil (or something else) as its false/empty-list value, you'll break anything that uses literal nils. And after gutting, all you gain is, what, the ability to use one more variable name? I think that's a different sort of restriction than being unable to redefine built-in functions.
Essentially, your suggestion is to treat literals as variables. But that's the point of nil and 2 and #\a and "this is a string": they're how you spell the basic constants out of which you build programs. I could philosophize about whether users should have the "freedom" to change what 2 means, but it devolves into the stuff of jokes (http://www.thinkgeek.com/tshirts-apparel/unisex/generic/60f5...).
Thanks for the excellent responses by yourself and waterhouse. I'll likely come back to this discussion several times in the near future (I want to try your patch), for now just a brief reply:
> More importantly, do you actually have a reason you want to rebind the canonical false value? I mean, basically all it could do is break. At least t is only boolean true because it's a symbol other than 'nil.
I don't have particular reason to redefine canonical false yet, but I did like the implications of all this on numbers for alists and would be very curious to hear reactions to that - maybe the idea is flawed or I need to explain it better [http://www.arclanguage.org/item?id=11714].
However, even if there were no immediate need to redefine 'nil, numeric symbols etc., I detect an ugliness with their redefinition being prohibited. I simply do not understand why ints would be untouchable when 'car, 'cdr, 'eval etc. - the true axioms of the language - can be reassigned in a heartbeat. If it has to be that only some of these symbols are sacred, I think it should be the axioms, not some literals. (Admittedly, there is some overlap, especially in 'nil territory.) Otherwise, it'd be cleaner to make everything rebindable or nothing so, and the former seems more in the spirit of Arc.
I detect an ugliness with their redefinition being prohibited.
But there's still a conceptual difference: numbers, strings, and characters are not variables to be redefined, but are syntax for constant values -- just like parentheses are syntax for "begin a list" and "end a list". It's like saying you should be allowed to change how the word "hello" is spelled.
Likewise, Arc works to make nil a literal value, (mostly) like a character or a string. Thus, redefining it is nonsensical. t isn't really a literal value, because any non-nil value is boolean true anyway. So, I agree that treating t as a variable could be allowed without breaking the current conceptual model.
I did like the implications of all this on numbers for alists and would be very curious to hear reactions to that
The reason 2 is the same as '2 isn't so much that quote special-cases numbers, it's that quote delays evaluation (which doesn't really happen for 2). On its own, foo evaluates to whatever it's bound to, so 'foo delays that. Compare with 2, which is "self-evaluating" -- as soon as we read it in, we know it's the number 2. Then '2 delays the evaluation of syntax that already had meaning before quote touched it. Hence, '2 is still just the number 2. Similarly for '#\a and '"a string".
You could make quote a special-casing operator, so '2 is different from 2 just because it's useful, but that doesn't let you redefine 2.
You could also change Arc so that there would be a layer between reading 2 and going "hey, that's the number 2". Then '2 would be more sensible and each 2 in your code could be a lookup to some value defaulting to...well, the number 2, I guess. But how do you distinguish 2-the-numeric-value and 2-the-variable if they're both spelled the exact same way? In the face of redefinition, (is (+ 1 1) 2) isn't an identity that would hold. What about extending this to less inductively-defined data types? How do you change #\a back to normal after (= #\a #\b)? Does it make (is "abc" "bbc") true? What if you first did (= "abc" "foo")?
The idea isn't just different, it creates a radically new language. That doesn't mean it's without merit. Off the top of my head, Common Lisp has reader macros that allow some syntax to be redefined, and PLOT (http://users.rcn.com/david-moon/PLOT/) lets you redefine syntax dynamically, though I'm not sure to what extent. But it's arguably one the first types of restrictions mentioned in http://www.paulgraham.com/ilc03.html (I don't mean to appeal to authority; it could just explain why Arc doesn't do this).
In ssyntax, everything is evaluated from left to right regardless of the operator.
Actually, no. . and ! are evaluated left-to-right in relation to each other, but there are currently three priority levels; from highest to lowest they are: (1) : and ~, (2) . and !, (3) &. Characters within the same level needn't be evaluated left-to-right, though . and ! are. For example,
arc> (ssexpand 'a.b:c.d) ; : takes precedence over .
(compose a.b c.d)
arc> (ssexpand 'a.b&c.d) ; . takes precedence over &
((a b&c) d)
arc> (ssexpand 'a:b&c:d) ; : takes precedence over &
(compose a b&c d)
Then, since & has lower precedence than ~, you can't do
arc> even&~odd
which causes Arc to hang (which is actually a bug).
Further, though ~ and : are in the same level, : takes priority over ~ regardless of order.
arc> (ssexpand '~a:~b)
(compose (complement a) (complement b))
If you're interested in rewriting code to use ssyntax, you can check out my sscontract library (and let me know if it's broken!): http://arclanguage.org/item?id=11179
Except you'd need to make iff's else clause default to returning nil. (I'm not sure why it doesn't do this now, but I don't use Anarki.)
It's an interesting idea, though. Currying in Arc has traditionally been a belabored topic with no clear "winner". One potential sticking point is that sometimes [] is used without _ to simply ignore the argument:
$ grep -P "^[^;]*\[[^\]_]*\]" *.arc
arc.arc: (let argsyms (map [uniq] (cdr expr))
arc.arc: (with (vars (map [uniq] places)
arc.arc: gargs (map [uniq] args)
[7 false positives elided (stuff in strings): 1 from blog.arc, 6 from news.arc]
news.arc: (flink [submit-login-warning url title showtext text])
news.arc: (flink [submit-page user url title showtext text retry*])
news.arc: (flink [submit-page user url title showtext text toolong*])
news.arc: (flink [submit-page user url title showtext text bothblank*])
news.arc: (flink [msgpage user spammage*])
news.arc: (flink [msgpage user toofast*])
news.arc: (flink [newpoll-page user title text opts retry*])
news.arc: (flink [newpoll-page user title text opts toolong*])
news.arc: (flink [newpoll-page user title text opts fewopts*])
news.arc: (flink [comment-login-warning parent whence text])
news.arc: (flink [msgpage user toofast*])
And last thing, I know it won't change but, I'd much more prefer x than _ as [] variable.
You're right, it probably won't change, but I think it's for a good reason -- indeed, the reason you mention: x is a common variable, so it's used in regular functions a lot. For example, in arc.arc:
(def testify (x)
(if (isa x 'fn) x [is _ x]))
(def adjoin (x xs (o test iso))
(if (some [test x _] xs)
xs
(cons x xs)))
(def intersperse (x ys)
(and ys (cons (car ys)
(mappend [list x _] (cdr ys)))))
It would apply pressure to not use x as a variable name in normal functions, which is livable but unpleasant. Compare to _, which has the aesthetic appeal of a blank to fill in and doesn't conflict with common variables.
Thanks for answer. You are right, my example doesn't work :p However, I still think that currying is important as it simplifies nested code a lot.
Maybe:
(map {+ 10} '(1 2 3))
Or maybe, it should just be a convention in arc that when not enough parameters are given, a currying function is returned.
So we could do:
(map (+ 10) '(1 2 3))
even if I know it may break a lot of things :p
-----
Also, I feel that, from a good coding perspective, x is great as a temporary variable in []. In fact, it might be a good thing that the programmer is forced to use a good variable name instead of x for normal arguments.
To take your example:
(def testify (x)
(if (isa x 'fn) x [is _ x]))
(def testify (type)
(if (isa type 'fn) type [is x type]))
The plan with intrasymbol syntax is (a) not to break traditional Lisp read and (b) to expand in place. If you have those two constraints, instead of just saying "ok, put any syntax anywhere," you can introduce syntax into Lisp without getting too unLispy.
No dice in vanilla Arc. There are only a couple of places ac doesn't call expand-ssyntax: in a function's argument list, quoted forms, and the variable of an assign. You'd need to patch ac.scm. For example, you could insert a global flag suitable for (declare 'ssyntax t/nil):
You could also modify ssyntax? to check specific symbols it shouldn't mess with. It already does this with +, ++, and _. You might just xdef the exception functions to different names, like exn-srclocs.
But if you made the changes as you suggested to ssyntax, then it would be easy enough to define a (w/o-ssynatax body) macro to temporarily disable ssyntax for a particular call.
They're just a convenience. You can specify a place where, if there is a function to call, you call it. You "hook" into certain pieces of code. news.arc uses them all over the place, like in the last line of
(def edit-page (user i)
(let here (edit-url i)
(shortpage user nil nil "Edit" here
(tab (display-item nil i user here)
(display-item-text i user))
(br2)
(vars-form user
((fieldfn* i!type) user i)
(fn (name val)
(unless (ignore-edit user i name val)
(when (and (is name 'dead) val (no i!dead))
(log-kill i user))
(= (i name) val)))
(fn () (if (admin user) (pushnew 'locked i!keys))
(save-item i)
(metastory&adjust-rank i)
(wipe (comment-cache* i!id))
(edit-page user i)))
(hook 'edit user i))))
I've not read news.arc thoroughly, so I don't know if this example actually works 100%, but humor me: Say at one point you need to diagnose a problem with edit-page, so you (defhook edit ...) to log the user on each call. After finding the problem, you need to change how edits work, so you (defhook edit ...) again to render an alert message that lets users know how editing has changed. But you don't want that message up forever, so after a week you (defhook edit (user i) nil).