Arc Forumnew | comments | leaders | submit | fallintothis's commentslogin

For Vim: http://arclanguage.org/item?id=10147

Then you can use :TOhtml: http://vimdoc.sourceforge.net/htmldoc/syntax.html#:TOhtml

-----


  $ mzscheme
  Welcome to Racket v5.2.1.
  > (load "as.scm")
  Use (quit) to quit, (tl) to return here after an interrupt.
  arc> ^Cuser break
  > (acompile "arc.arc")
  [...output elided...]
  > (exit)
  $ head arc.arc.scm
  (begin
    (let ((zz
           (ar-funcall2
            _annotate
            'mac
            (let ((| do| (lambda args `((fn () ,@(ar-nil-terminate args))))))
              | do|))))
      (namespace-set-variable-value! '_do zz)
      zz))

-----

1 point by steeleduncan 4458 days ago | link

thank you

-----

3 points by fallintothis 4462 days ago | link | parent | on: Discussion about macros in Arc

I.e., "party on zck's bitbucket!" :)

I think the discussion might be interesting to other folks here. And at least bitbucket has inline code formatting!

-----

3 points by zck 4462 days ago | link

Yeesh, I can feel my mind expanding. It's fighting it, but it's going.

Thanks again for the tutoring. I can't help but think this would be an order of magnitude easier in person, but c'est la vie.

-----

3 points by fallintothis 4460 days ago | link

Sure thing! I was a teacher in a previous life, so I enjoy helping people learn...to say nothing of whether I'm any good at it. :)

-----


Note that assert-same requires the expected value before the test-value. This is needed for pretty, pretty messages when the assert fails:

Maybe I'm just tired, but I first took this to mean that it was impossible for assert-same to be defined so that its arguments were (actual expected (o fail-message)). Now I realize that you just mean the positions of your expected/actual values are important.

One design thought: the name assert isn't taken by Arc. You could simplify the interface while generalizing it by just separating assert from the things it's asserting.

So, the basic assert would essentially be assert-t, and the other three could follow. Something like

  (assert-t actual (o fail-message))
  ; becomes
  (assert actual (o fail-message))
  ; or, without the custom message
  (assert actual)

  (assert-nil actual (o fail-message)) 
  ; becomes
  (assert (no actual) (o fail-message))
  ; or, without the custom message
  (assert:no actual)

  (assert-error actual (o expected-error))
  ; becomes
  (assert (error actual (o expected-error)) (o fail-message))
  ; or, without the custom message
  (assert:error actual (o expected-error))

  (assert-same expected actual (o fail-message))
  ; becomes
  (assert (same expected actual) (o fail-message))
  ; or, without the custom message
  (assert:same expected actual)
Then, you define error and same to "do the right things". same would probably need to throw an error when the arguments were mismatched, so that you could generate the nice message---assuming that assert would catch errors and report them as failures. error would be easy to define. Maybe something like

  (mac assert (condition (o fail-message))
    `(on-err (fn (c) ...fail...)
             (fn () (unless ,condition ...fail...))))

  (mac same (expected actual)
    (w/uniq (e a)
      `(with (,e ,expected ,a ,actual)
         (or (iso-that-works-on-hash-tables ,e ,a)
             (err "" ',actual 'returned ,a 'wanted ,e))))) ; modulo prettiness

  (mac error (expr (o expected-error))
    `(on-err (fn (c) ...pass, modulo expected-error...)
             (fn () ,expr ...fail if we get here without an error...)))
Solid work, though!

-----

2 points by zck 4464 days ago | link

Thanks for the feedback, both here and on the bug in the bitbucket tracker.

I'm not sure of my feelings on changing all the asserts to be just one. On one hand, it is simpler to have just the one command. On the other, it seems like a much more complicated interface, as you would never guess how to use it from, for example, the method signature. assert-t, assert-same et. al. seem like a lower conceptual load.

It reminds me of the arguments over CL's loop macro -- who knows all of it? I can never remember how to do much of what I want. Of course, this is much simpler than loop. Maybe I'll implement it and see how it feels.

-----


The error you're getting from fancy-combine2 is because you have a double-unquote. You neglected to remove the unquotes from sym1 and sym2. The correct form would be

  (mac fancy-combine (sym1 sym2)
    `(consume-symbol ,(generate-symbol sym1 sym2)))
It might help to have a user-land defined quasiquote macro, to see how it works. I implemented such a macro here: https://bitbucket.org/fallintothis/qq

Using qq.arc, we can see that my solution is to use this expression:

  arc> (macex1 '(quasiquote
                  (consume-symbol (unquote (generate-symbol sym1 sym2)))))
  (list (quote consume-symbol) (generate-symbol sym1 sym2))
On the other hand, your version is like this:

  arc> (macex1 '(quasiquote
                  (consume-symbol
                    (unquote (generate-symbol (unquote sym1)
                                              (unquote sym2))))))
  (list (quote consume-symbol) (generate-symbol (unquote sym1) (unquote sym2)))
Hence, you get an error about unquote being undefined, because Arc doesn't actually define quasiquote or unquote as macros. They're just special identifiers that are basically parsed away before evaluation (assuming quasiquotes/unquotes are balanced). However, loading qq.arc defines an unquote macro, so instead of the error you had, you'll get this:

  arc> (fancy-combine2 a b)
  Error: "unquote not allowed outside of a quasiquote: a"
which makes it a bit more obvious what the error is.

-----

4 points by zck 4474 days ago | link

Ah, fantastic! Thanks for the hint.

For some reason, I had in my head that, inside quasiquote in a macro, you need to unquote every variable you want to evaluate before returning the code to be executed. Note that all my examples have ,sym1 and ,sym2 (except fancy-combine4, but that's deliberately executing the code before the returned generated code).

I guess the moral of the story here is that ,(...) evaluates the entire sexp, and puts the value there. I'll have to do more reading about macros.

-----

4 points by fallintothis 4474 days ago | link

I guess the moral of the story here is that ,(...) evaluates the entire sexp, and puts the value there.

Yup! If your quasiquoted expression only contains unquotes, the expansion is simple. Basically,

  `(sexp1 sexp2 ... ,sexpn ...)
will expand into

  (list 'sexp1 'sexp2 ... sexpn ...)
This also applies recursively, so that

  `(sexp1 (subexpr1 ,subexpr2))
expands into

  (list 'sexp1 (list 'subexpr1 subexpr2))
With unquote-splicing, you can think of quasiquote expanding into cons, so

  `(sexp1 sexp2 ,@sexp3)
will expand into

  (cons (list 'sexp1 'sexp2) sexp3)
If you're interested, I encourage you to look over my implementation of quasiquote in Arc. It's actually pretty simple (175 lines with comments), and might help clarify how quasiquotation works.

I'll have to do more reading about macros.

I think you seem to have the mental model for macros down. And I've always said that macros aren't that magical, because they fall out as a natural consequence of the language. Hell, here's a simple Arc "interpreter" that shows how macros are handled differently from functions:

  (def interpret (expr)
    (if (acons expr)
        (let op (interpret (car expr))
          (if (isa op 'mac) (interpret (apply (rep op) (cdr expr)))
              (isa op 'fn)  (apply op (map interpret (cdr expr)))
                            (eval expr))) ; punt on special forms (fn, if, etc.)
        (maybe-lookup-name expr)))

  (def maybe-lookup-name (expr)
    (if (and (isa expr 'sym) (bound expr))
        (eval expr)
        expr))
Here, interpret is really just another name for eval. Macros are simply functions whose inputs are unevaluated code. They construct some other bit of unevaluated code, and that result gets evaluated.

Quasiquote is then just a nice way to construct lists, whether it's unevaluated code for a macro to return or whatever. Its syntax takes some getting used to, but it comes with practice. Happy hacking!

-----

4 points by fallintothis 4480 days ago | link | parent | on: Help me customize news.arc

Editing news.arc won't "reload" your changes. If you write the code to the file, it won't actually execute that code. Does that make sense?

You want to go back to the arc> prompt (where you started (nsv)) and do something to get that code to run. You could do this in a few ways. You could do:

  arc> (load "news.arc")
which will reload the changes you saved to the news.arc file. It might look crazy, because it prints out a bunch of messages that look like

  *** redefining logins-page
It'll do that because it's reloading the entirety (!) of news.arc, which includes a bunch of other code. Thus, there are warnings about "redefining" certain code. But as long as you didn't actually change the code in question, it should be fine.

At the end of the day, this is probably the best way to go, despite all the intimidating warning messages. Because if you edit the news.arc file, then the changes you make will be saved in case you ever need to restart the forum in the future.

But, for the sake of completeness, I'll explain how you can also just edit the variables by hand at the prompt. So, instead of changing news.arc to say

  (= this-site*    "Match Fixing Scandals"
     site-url*     "http://news.yourdomain.com/"
     parent-url*   "http://www.yourdomain.com"
     favicon-url*  ""
     site-desc*    "What this site is about."               ; for rss feed
     site-color*   (color 180 180 180)
     border-color* (color 180 180 180)
     prefer-url*   t)
and reloading news.arc, you could actually just put the entire thing above (called an expression) into the arc> prompt:

  arc> (= this-site*    "Match Fixing Scandals"
          site-url*     "http://news.yourdomain.com/"
          parent-url*   "http://www.yourdomain.com"
          favicon-url*  ""
          site-desc*    "What this site is about."               ; for rss feed
          site-color*   (color 180 180 180)
          border-color* (color 180 180 180)
          prefer-url*   t)
This will execute the code, thus modifying your settings.

You could also use simpler expressions---or, really, any Arc code you want. If you weren't a coder before, you are one now! :)

The expression above of the form (= a b c d ...) can be used to change the values of any number of variables (setting a to b, c to d, etc.), which will control how the site displays. So, you could do something like

  arc> (= this-site* "Whatever")
  "Whatever"
  arc> (= site-url* "google.com" parent-url* "wikipedia.org")
  "wikipedia.org"
whenever you want.

One of these settings you'll want to change is buried deep inside of news.arc (about 400 lines down), so it's hard to spot. But, you can change these variables, too:

  (= up-url* "grayarrow.gif" down-url* "graydown.gif" logo-url* "arc.png")
For your purposes, you can do something like

  arc> (= logo-url* "some-other-logo.png")
and make sure that some-other-logo.png is in your static/ directory.

Hope that helps!

-----

2 points by pier0 4480 days ago | link

fallintothis,

thanks for your clear explanation.

I tried to put the entire expression into the arc> prompt and also tried to use simpler expressions, but I still can't get "My Forum" to change.

I've also reloaded news.arc several times and I'm not sure if it means anything, but when I go back to the arc> prompt and enter arc> (load "news.arc") I get nil

and only after loading news.arc a second time I get the "* redefining" messages

I remember that to run news.arc the first time I also used (nsv) so I tried that as well and for what is worth I got the following error:

  rm: cannot remove ‘arc/news/story/*.tmp’: No such file or directory
  load items:
  user break
  context...:
   /home/ubuntu/arc/ac.scm:1031:20
    gs1259
  user break
  context...:
   /home/ubuntu/arc/ac.scm:1031:20
    gs1259
  Error: "tcp-listen: listen failed\n  port number: 8080\n  system error: Address already in use; errno=98"
  arc>

-----

4 points by thaddeus 4480 days ago | link

Hmmm it's been a really long time since I looked at the code, but I would try two things.

1. Enter this-site* at the prompt to confirm the change took place.

2. Abort the session, I.e such that the arc prompt is killed. Then goto the webpage and make sure its no longer running news (just to confirm the abort occurred and/or is not somehow running a past instance), then reload arc again.

-----

2 points by akkartik 4479 days ago | link

Yeah these are good suggestions. The "address already in use" error suggests that you might have multiple copies of arc running, so that you're making changes to the wrong copy. Use the commands 'ps' and 'kill' to look for the other copies and stop them.

http://stackoverflow.com/questions/3510673/find-and-kill-a-p...

-----

2 points by pier0 4479 days ago | link

I used the command ps aux | grep 'news.arc' and it returned only one copy running, but I suspect that's not right.

And your comment about multiple copies also got me thinking that from the main Arc directory to go into the Arc prompt maybe I shouldn't have been using $ mzscheme -f as.scm

Was I supposed to use that just once to run news.arc for the first time?

-----

3 points by akkartik 4479 days ago | link

No, you want to run:

  $ ps aux |grep mzscheme
ps doesn't know about news.arc, that's just one of the files loaded by mzscheme.

I didn't understand the second and third paragraphs. Can you tell me more about what version of arc you downloaded and how you're running it?

-----

2 points by pier0 4479 days ago | link

I did as you suggested and found a second process running, Then I run this

kill $(ps aux | grep '[m]zscheme' | awk '{print $2}')

and it killed one. After it was just a matter of starting-restating Arc with the changes in news.arc.

And next is the logo. Thanks for your precious advice.

PS In the previous post I was starting to doubt that I'm not supposed to use mzscheme -f as.scm as a command to get to the Arc prompt

-----

2 points by akkartik 4479 days ago | link

Great!

Out of curiosity, how do you stop the server once you start it?

-----

2 points by pier0 4475 days ago | link

I eventually connected the problem with the multiple copies of Arc running with having a detached screen, so I stopped that and closed the terminal.

After doing so the news site was down, which I believe is what Thaddeus was recommending to happen.

Then I had to restart it and detach the screen and start the process again.

It is not ideal, but I think it works.

-----

2 points by thaddeus 4475 days ago | link

Assuming you're using 'GNU screen' you also have the option to re-attach to an existing session using the 'screen -r' command. Using 'screen -ls' will list out all the sessions should you not be sure, or have more than one.

That aside, most developers will do development changes on a local machine where they need not attach/reattach and this way you wouldn't need to troubleshoot your code and the host environment at the same time.

Then you create a stable deployment process. eg. Backup the old code, drop in the new code, re-attach to the existing session and either load your changes or restart the program if you're ok with some nominal downtime.

Hope that helps.

-----

2 points by pier0 4479 days ago | link

I couldn't understand what you meant by "make sure its no longer running news" but now I know.

Basically I got a bad gateway error and the web page was no longer accessible until I reloaded news.arc

  arc> (load "news.arc")
  arc> (nsv)
Thanks thaddeus

-----

3 points by thaddeus 4477 days ago | link

No problemo and yeah, in retrospect, I could have chosen better terminology and been much more descriptive, but that's one of the things you will enjoy about the arc forum... You just keep asking and, generally speaking, people are very helpful. After all, I learned how to program by just doing what you are, running the news app, reading the arc code and relying on this forum for help along the way.

-----


Is Racket not an available package? Googling "yum install racket" gives the following instructions for installing Racket on Fedora:

http://cha1tanya.com/blog/2013/06/05/installing-racket-on-fe...

http://linuxg.net/how-to-install-drracket-on-fedora-18-and-f...

Otherwise, Googling "How can I install the Racket on CentOS?" gives:

http://lists.racket-lang.org/users/archive/2011-April/044979... (from 2011, so could very well be outdated)

http://racket-lang.org/download/ (all else fails)

-----


https://plus.google.com/115420443999474491901/posts/dF12ruJc...

Hm. I didn't realize my name was Gabriel Scherer and I had already made a comment.

That's handy, because it saves me the trouble of writing it all out.

-----

4 points by fallintothis 4530 days ago | link | parent | on: Nested Macros

First, you have to understand what the quasiquote and unquote are doing. It doesn't seem at first glance like you're clear on that, so a mini-lesson:

  arc> 'the-basic-purpose-of-quote-is-to-prevent-a-symbol-from-being-evaluated
  the-basic-purpose-of-quote-is-to-prevent-a-symbol-from-being-evaluated
  arc> '(quote can be used on any expression --- including a list)
  (quote can be used on any expression --- including a list)
  arc> (list 'you 'can 'think 'of ''(a b c) 'as 'shorthand 'for '(list 'a 'b 'c))
  (you can think of (quote (a b c)) as shorthand for (list (quote a) (quote b) (quote c)))
  arc> `quasiquote-is-pretty-much-just-like-quote
  quasiquote-is-pretty-much-just-like-quote
  arc> (list 'so '`(a b c) 'is 'like '(list 'a 'b 'c))
  (so (quasiquote (a b c)) is like (list (quote a) (quote b) (quote c)))
  arc> `(but suppose you want to write (list 'a 'b c) --- where the last element has no quote)
  (but suppose you want to write (list (quote a) (quote b) c) --- where the last element has no quote)
  arc> `(then quasiquote gives you a shorthand by using "unquote")
  (then quasiquote gives you a shorthand by using "unquote")
  arc> `(so `(a b ,c) is like (list 'a 'b c) and `(a ,b c) is like (list 'a b 'c) etc)
  (so (quasiquote (a b (unquote c))) is like (list (quote a) (quote b) c) and (quasiquote (a (unquote b) c)) is like (list (quote a) b (quote c)) etc)
  arc> `(thus this list will have 4 instead of (+ 2 2) right here: ,(+ 2 2))
  (thus this list will have 4 instead of (+ 2 2) right here: 4)
  arc> `(because `(a b ,(+ 2 2)) is like (list 'a 'b (+ 2 2)))
  (because (quasiquote (a b (unquote (+ 2 2)))) is like (list (quote a) (quote b) (+ 2 2)))
  arc> (list 'see? 'a 'b (+ 2 2))
  (see? a b 4)
  arc> 'voila
  voila
With that understood, each isn't doing what you think it is.

  arc> (each x '(1 2 3)
         (prn "\"each\" is used for side-effects on the variable x = " x)
         (prn "but ultimately, it will return nil")
         (prn "we can call pure functions on x")
         (+ x 1)
         (prn "but we won't see anything they return")
         x
         (* x 12)
         (when (is x 3)
           (prn "witness: the next line is the return value of \"each\"!")))
  "each" is used for side-effects on the variable x = 1
  but ultimately, it will return nil
  we can call pure functions on x
  but we won't see anything they return
  "each" is used for side-effects on the variable x = 2
  but ultimately, it will return nil
  we can call pure functions on x
  but we won't see anything they return
  "each" is used for side-effects on the variable x = 3
  but ultimately, it will return nil
  we can call pure functions on x
  but we won't see anything they return
  witness: the next line is the return value of "each"!
  nil
This is because each is a macro that (on a list) expands

  (each x xs
    (do-something x)
    (do-something-else x))
into something like

  ((rfn loop-around (elements)
     (when (acons elements)
       (let x (car elements)
         (do-something x)
         (do-something-else x))
       (loop-around (cdr elements))))
   xs)
You can see that when we get to the end of the list xs, the variable elements is passed in as nil. Because (acons nil) is nil, we don't return anything from the overall when expression. As such, you can be sure that the return value of each on a list is always going to be nil, because that's how it ends its recursive journey.

Thus,

  arc> `(if I "unquote" (each x '(1 2 3) x) into this list I just get ,(each x '(1 2 3) x))
  (if I "unquote" (each x (quote (1 2 3)) x) into this list I just get nil)
What you actually want is to accumulate the results of manipulating each element of the list. That's what map is for:

  arc> (map (fn (x) (+ x 1)) '(1 2 3))
  (2 3 4)
  arc> `(if I "unquote" (map [* _ 12] '(1 2 3)) into this list I get ,(map [* _ 12] '(1 2 3)))
  (if I "unquote" (map (fn (_) (* _ 12)) (quote (1 2 3))) into this list I get (12 24 36))
So, let's take a look at how

  (mac css (sel props . nest)
    `(do ,(pr (string sel "{"))
      ,(gen-css-properties props)
      ,(map [gen-nested-css _ sel props] nest)))
works out. But let's take it slow and just use macex1 to expand the macro by one step---I don't want to get lost in recursion. Because your macro is making calls to pr at macro-expansion time, I'm going to take the liberty of drawing it out even further, so as the output from the prompt doesn't get too confusing:

  arc> (let macro-expansion (macex1 '(css "#foo" (id 5) (".bar" (z-index 2))))
         (prn)
         (ppr macro-expansion)
         (prn))
  #foo{
  (do "#foo{"
      (do (if 5 (pr "id:" 5 ";"))
          (pr "}"))
      ((css "#foo .bar"
            (id 5 z-index 2)
            nil)))
  nil
Now, we get to see the problem of using the unquote versus unquote-splicing (,@). The unquote will just shove its argument into the list. Because we're unquoting another list itself, you can see the result of the call to gen-nested-css gets stuck with an extra layer of parentheses. In the expansion, it's like saying

  arc> ((+ 2 2))
  Error: "Function call on inappropriate object 4 ()"
instead of

  arc> (+ 2 2)
  4
However, if you use unquote-splicing, the elements of the list will get "inlined" into the overall list that the quasiquote is constructing. E.g.,

  arc> `(symbols wrapped in parens because of unquote: ,'(a b c))
  (symbols wrapped in parens because of unquote: (a b c))
  arc> `(symbols without parens because of unquote-splicing: ,@'(a b c))
  (symbols without parens because of unquote-splicing: a b c)
So,

  (mac css (sel props . nest)
    `(do ,(pr (string sel "{"))
      ,(gen-css-properties props)
      ,@(map [gen-nested-css _ sel props] nest)))
gives us

  arc> (let macro-expansion (macex1 '(css "#foo" (id 5) (".bar" (z-index 2))))
         (prn)
         (ppr macro-expansion)
         (prn))
  #foo{
  (do "#foo{"
      (do (if 5 (pr "id:" 5 ";"))
          (pr "}"))
      (css "#foo .bar"
           (id 5 z-index 2)
           nil))
  nil
Now, whether this is the desired expansion at the end of the day is a matter of debugging. Good luck! :)

Recommendation: with these points (I hope) cleared up, look closer at html.arc. If you had modeled your code after it more precisely, you probably wouldn't have had these issues. But hey, that's how we learn.

I catch some resistance sometimes when I suggest learning Arc by reading Arc, but the source code is not only a definitive reference for what functionality Arc provides, it also gives you a wealth of idiomatic code. And I can't think of a better way to answer "how does [some function] work?" than to look up its usually-terse definition.

-----

3 points by fallintothis 4534 days ago | link | parent | on: Insort is not truly destructive?

Your version doesn't quite work as-is:

  arc> (= y (= x '(1 3 5)))
  (1 3 5)
  arc> (insort < 2 x)
  (1 2 3 5)
  arc> x
  (1 2 3 5)
  arc> y
  (1 2 3 5)
  arc> (insort < 0 x)
  (0 1 2 3 5)
  arc> x
  (0 1 2 3 5)
  arc> y
  (0 1 2 3 5)
  arc> (insort < 6 x)
  (0 1 2 3 5 6)
  arc> x
  (0 1 2 3 5 6)
  arc> y
  (0 1 2 3 5 6)
  arc> (= y (= x nil))
  nil
  arc> (insort < 1 x)
  nil
  arc> x
  nil
  arc> y
  nil
Here's a version I wrote for my own edification (basically, a more complicated version of yours):

  (def destructive-cons (elt seq)
    ; Note: (push elt seq) won't work, because push is a macro on the "place",
    ; and seq isn't the proper "place" to mutate (push will just mutate the local
    ; binding of seq).  This function will actually mutate the cons cell being
    ; pointed at by seq.
    (let (first . rest) seq
      (scar seq elt)
      (scdr seq (cons first rest)))
    seq)

  (def insorter (test elt seq)
    (if (no seq)
         (list elt)
        (test elt (car seq))
         (destructive-cons elt seq)
        (do1 seq
             ((afn (prev cell)
                (if (or (no cell) (test elt (car cell)))
                    (scdr prev (cons elt cell))
                    (self cell (cdr cell))))
              seq (cdr seq)))))

  (mac insorted (test elt seq)
    `(zap [insorter ,test ,elt _] ,seq))
Writing it made me realize the issues with making a "truly destructive" insort:

  arc> (= y (= x '(1 3 5)))
  (1 3 5)
  arc> (insorted < 2 x)
  (1 2 3 5)
  arc> x
  (1 2 3 5)
  arc> y
  (1 2 3 5)
  arc> (insorted < 0 x)
  (0 1 2 3 5)
  arc> x
  (0 1 2 3 5)
  arc> y
  (0 1 2 3 5)
  arc> (insorted < 6 x)
  (0 1 2 3 5 6)
  arc> x
  (0 1 2 3 5 6)
  arc> y
  (0 1 2 3 5 6)
  arc> (= y (= x nil))
  nil
  arc> (insorted < 1 x)
  (1)
  arc> x
  (1)
  arc> y
  nil
No matter how you try, there's still the edge case with nil, on which you can't scar/scdr.

  arc> (= x nil)
  nil
  arc> (scar x 1)
  Error: "set-car!: expected argument of type <pair>; given nil"
  arc> (scdr x '(2))
  Error: "set-cdr!: expected argument of type <pair>; given nil"
So it appears Arc's model of "places" can't really handle references/aliases that well. Indeed, push, swap, rotate, pop, pushnew, pull, togglemem, and the like are "broken", too, if we expect them to modify the _content_ of their arguments instead of simply where the arguments point. E.g.,

  arc> (= y (= x '(a b c)))
  (a b c)
  arc> (= z (= w '(1 2 3)))
  (1 2 3)
  arc> (swap x w)
  (a b c)
  arc> x
  (1 2 3)
  arc> y
  (a b c)
  arc> z
  (1 2 3)
  arc> w
  (a b c)
In a way, I can see that being the right behavior for swap, but not for insort. I suppose it's at least somewhat consistent: just alter your expectations of "destructive" operators, since they'll all (near as I can tell) just modify where their input "places" are pointing. Not that I'm ready to write off the issue that way, it's just I don't have a solution and think it gets complicated depending on the operators in question. :)

-----

2 points by dram 4534 days ago | link

Good catch.

About the nil problem, maybe we should nil terminate list this way: (1 2 nil), instead of (1 2 . nil). just a joke. :)

Anyway, mutable pair is just a mess, I feel I have some understanding why Racket get rid of set-car! and set-cdr!.

-----

1 point by akkartik 4534 days ago | link

"..just alter your expectations of destructive operators.."

Yeah, I agree with this. I weakly think (without evidence) that arc's destructive ops are more functional, and it encourages a better style to not constantly make assumptions about precisely which cons cells go where.

On the other hand, a set of 'alias-friendly' functions could coexist with the existing primitives.

Hmm, I wonder if the notion of boxes would help build alias-friendly operations.

-----

More