Arc Forumnew | comments | leaders | submit | fallintothis's commentslogin
1 point by fallintothis 5675 days ago | link | parent | on: What does 'nil buy us?

Per the comment above ar-false?

  ; 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.

-----


It's entirely possible. Here's a proof-of-concept patch that seems to accomplish most of the t and nil rebinding.

  $ diff -u old-ac.scm new-ac.scm
  --- old-ac.scm  2010-05-03 09:04:07.000000000 -0700
  +++ new-ac.scm  2010-05-03 10:11:33.000000000 -0700
  @@ -17,7 +17,9 @@
   (define (ac s env)
     (cond ((string? s) (ac-string s env))
           ((literal? s) s)
  -        ((eqv? s 'nil) (list 'quote 'nil))
  +        ((eqv? s 'nil) (if (bound? 'nil)         ;XXX
  +                           (ac-var-ref 'nil env)
  +                           (list 'quote 'nil)))
           ((ssyntax? s) (ac (expand-ssyntax s) env))
           ((symbol? s) (ac-var-ref s env))
           ((ssyntax? (xcar s)) (ac (cons (expand-ssyntax (car s)) (cdr s)) env))
  @@ -396,8 +398,8 @@
     (if (symbol? a)
         (let ((b (ac b1 (ac-dbname! a env))))
           (list 'let `((zz ,b))
  -               (cond ((eqv? a 'nil) (err "Can't rebind nil"))
  -                     ((eqv? a 't) (err "Can't rebind t"))
  +               (cond ;((eqv? a 'nil) (err "Can't rebind nil"))
  +                     ;((eqv? a 't) (err "Can't rebind t"))
                        ((lex? a env) `(set! ,a zz))
                        (#t `(namespace-set-variable-value! ',(ac-global-name a)
                                                            zz)))
  @@ -747,7 +749,7 @@
   (xdef is (lambda args (pairwise ar-is2 args)))

   (xdef err err)
  -(xdef nil 'nil)
  +;(xdef nil 'nil)
   (xdef t   't)

   (define (all test seq)
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
It's a pretty horrible solution:

  $ rlwrap mzscheme -f as.scm
  arc> (def f (x) (cons x nil))
  #<procedure: f>
  arc> (f 5)
  (5)
  arc> (= nil 10)
  10
  arc> (f 5)
  (5)
  arc> (def g (x) (cons x nil))
  #<procedure: g>
  arc> (g 5)
  (5 . 10)
But as I said, just a proof of concept.

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...).

-----

1 point by evanrmurphy 5676 days ago | link

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.

-----

2 points by fallintothis 5676 days ago | link

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).

-----


Is there a good rule-of-thumb for avoiding this?

If there is, I'd like to know. Seems to be a wart: in the functional position, names are interpreted as macros if they were globally bound as such.

  arc> (mac m (x) `(list 'expanded ',x))
  #(tagged mac #<procedure: m>)         
  arc> (def foo (m) m)
  #<procedure: foo>
  arc> (def bar (m) (+ m 1))
  #<procedure: bar>
  arc> (def baz (m index) (m index))
  #<procedure: baz>
  arc> (foo 5)
  5
  arc> (bar 5)
  6
  arc> (baz "abc" 0)
  (expanded index)
There was a halfhearted thread about this at http://arclanguage.org/item?id=9696, if it's any consolation.

-----


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

-----

1 point by evanrmurphy 5686 days ago | link

Very clarifying, thanks. I stand corrected. :)

-----

5 points by fallintothis 5686 days ago | link | parent | on: Arc suggestion

  (trues [if [odd] [+ 10]] '(1 2 3 4 5))
The currying idea is sound, but I don't see how this example would work. That is, I can see that

  [+ 10]
maps to

  (fn _ (apply + 10 _))
But applying the same transformation to

  [if [odd] [+ 10]]
yields

  (fn _ (apply if [odd] [+ 10] _)) ; ?
You could use another function like Anarki's iff (http://github.com/nex3/arc/blob/master/lib/util.arc#L198):

  (trues (iff odd [+ 10]) '(1 2 3 4 5)) ; note that [odd] == odd
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.

-----

2 points by d0m 5686 days ago | link

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.

http://arclanguage.org/item?id=2185

-----

2 points by evanrmurphy 5688 days ago | link

That's the thread I needed, thanks.

-----

2 points by fallintothis 5694 days ago | link | parent | on: New to Arc

Common question lately! The previous discussions have a lot of info.

http://arclanguage.org/item?id=11617

http://arclanguage.org/item?id=11604

http://arclanguage.org/item?id=11583

-----

1 point by messel 5694 days ago | link

Thanks just came across this question and answers. My bad for duplication. http://arclanguage.org/item?id=11583

Just updated mzscheme to the latest and grabbed arc3.1 will explore some tutorial like material asap

-----

1 point by fallintothis 5694 days ago | link

My bad for duplication.

No biggie. This place moves slow enough that you can default to http://arclanguage.org/newest and http://arclanguage.org/newcomments, where you would've seen these. Let us know if you have any questions as you go!

-----

2 points by fallintothis 5696 days ago | link | parent | on: Infomation

See the discussions at http://arclanguage.org/item?id=11604 and http://arclanguage.org/item?id=11583.

-----

1 point by fallintothis 5706 days ago | link | parent | on: Is there a way to 'escape' ssyntax?

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):

  @@ -57,8 +57,11 @@
         (number? x)
         (eq? x '())))

  +(define ssyntax #t)
  +
   (define (ssyntax? x)
     (and (symbol? x)
  +       ssyntax
          (not (or (eqv? x '+) (eqv? x '++) (eqv? x '_)))
          (let ((name (symbol->string x)))
            (has-ssyntax-char? name (- (string-length name) 1)))))
  @@ -1420,6 +1423,7 @@
   (xdef declare (lambda (key val)
                   (let ((flag (not (ar-false? val))))
                     (case key
  +                    ((ssyntax)        (set! ssyntax        flag))
                       ((atstrings)      (set! atstrings      flag))
                       ((direct-calls)   (set! direct-calls   flag))
                       ((explicit-flush) (set! explicit-flush flag)))
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.

-----

1 point by shader 5706 days ago | link

Yeah, I guess I'm too used to using Anarki ;)

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.

-----

1 point by akkartik 5706 days ago | link

Oh, so the ssyntax implementation in anarki would permit PLT functions with colons in them?

-----

1 point by shader 5704 days ago | link

From my preliminary tests, it seems that using

  (($ fn:name) arg1 arg2)
works just fine, though ($.fn:name arg1 arg2) doesn't.

So, yes, you can use PLT functions with ssyntax on Anarki

-----

3 points by fallintothis 5707 days ago | link | parent | on: What's the purpose of "hook"?

You could call a named function, but hooks are only called if they're defined, since hook is written as

  (def hook (name . args)
    (aif (hooks* name) (apply it args)))
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).

-----

1 point by thaddeus 5707 days ago | link

Ahhh... Thank you - I get it. I can totally see using hook for logging purposes and I can imagine a bunch of other uses for it too...

example:

(= mydata (fromjson "{\"first\":\"Edgar\",\"last\":\"Poe\",\"age\":\"23\",\"dob\":\"Jan 19 1809\"}"))

(= datatypes (obj "first" 'text "last" 'text "age" 'integer "dob" 'date))

(= mydatabase (table))

  arc> mydata
  #hash(("last" . "Poe") ("first" . "Edgar") ("age" . "23") ("dob" . "Jan 19 1809"))

  (defhook integer (val)
    (coerce val 'int))

  (defhook date (val)
    (upcase val))

  (def storedata (mydb typedb)
   (each field (keys mydb)
     (fill-table mydatabase 
        (list field (aif (hook typedb.field mydb.field) it mydb.field))))
    mydatabase)

  arc> (storedata mydata datatypes)
  #hash(("last" . "Poe") ("age" . 23) ("first" . "Edgar") ("dob" . "JAN 19 1809"))
It should have clicked in when I saw aif, but it didn't.

-----

More