Arc Forumnew | comments | leaders | submit | drcode's commentslogin
5 points by drcode 6496 days ago | link | parent | on: Possible bug in using + for lists

In Common Lisp '() and () should be identical and are made so through a compiler hack, from my understanding.

PG has indicated in the past (in the ANSI CL book, I believe) that he doesn't like this behavior, because the missing quote is a bit confusing.

It sounds to me though like this the error is a bug, since in arc they otherwise seem to be treated as identical.

-----


to format code in comments, prepend them with an empty line and indent the lines of code at least 2 spaces.

-----

1 point by blatta 6498 days ago | link

Thanks!

-----

6 points by drcode 6498 days ago | link | parent | on: On Lisp as a guide to Arc

FYI- It's worth finding, if you didn't know:

http://www.amazon.com/gp/offer-listing/0130305529/ref=dp_olp...

-----

6 points by tjr 6498 days ago | link

I've seen the price of a used copy of On Lisp rise over the years... now circa $400? With a PDF available free of charge from pg's website?

I highly value good books, and this is one of the best CS books out there, but even so, I'm surprised at the market value for a used copy.

Not complaining, just observing and wondering. Carry on.

-----

1 point by drcode 6499 days ago | link | parent | on: core language thingies

I like this idea! It could aid in terseness- Though it's a little line-noisy...

-----

1 point by drcode 6499 days ago | link | parent | on: Value of iteration expressions

looks good to me.

-----


I don't know what it is, but pattern matching like this just doesn't feel very "arcy" to me (and I'm not claiming my ideas are superior or anything...)

I think it has to do with the fact that Haskell uses pattern matching as a comprehensive way for defining all functions. Using a pattern matching library in arc means that for every function I write I would have to decide whether to use the pattern matching definition, or a regular definition, which feels inelegant...

I think an argument could be made to make pattern matching (very much like this) the default behavior for all arc functions... but short of that, I, personally, would probably not use a library like this very often...

However, it looks like an elegant implementation of the concept, so if I had to ever write some code with extremely hairy destructuring I definitely might change my mind an use it in a limited section of code...

-----

7 points by almkglor 6499 days ago | link

> if I had to ever write some code with extremely hairy destructuring I definitely might change my mind an use it in a limited section of code...

Which is the point of every library for every language, anyway. I'd be hard pressed trying to use a matrix library in an IRC bot.

Personally, I find pattern matching to be a powerful way of not having to fiddle with 'caris and what not. I just say "if the user puts this and that and this, then do it this way". I'd argue it removes some amount of bugs, too - I caught a bug in pg's 'varline function because I was trying to convert it to pattern-matching form. Mucking about with car/cdr and friends feels rather low-level to me; and if Arc is attempting to be the highest of high level languages, it certainly shouldn't force the user to think in terms of list nodes.

-----


The basic idea is:

  arc> (def foo ((a . b))
                a)
  #<procedure:  foo>
  arc> (foo nil)
  nil
...the reason it returns nil is I think because (car nil) in arc is nil. I think this is the Right Thing overall, even though an empty list doesn't really have a car.

However, in the case of parameter destructuring we could do better, because during destructuring we could (if it worked this way) supply default optional values to have more intelligent handling if a part of a destructuring encounters an empty list and "runs out" of values to destructure. It would look like this:

  arc> (def foo (((o a 'falafel) . b))
                a)
  #<procedure: foo>

  arc> (foo '(bar baz))
  bar

  arc>(foo nil)
  falafel
The value of this would be: 1. List processing functions, among others, could tell when they run out of values for destructuring by checking for the magic optional value 2. It might be possible to get this behavior "for free" without growing the source of arc, since it seems like it might just be a generalization of current destructuring/optional support.

-----

2 points by nlavine 6498 days ago | link

Hmm. A quick check in the arc interpreter reveals that (car nil) and (cdr nil) are both nil, so you're right about that.

However, there could be another reason this is working. In your particular example, the full expanded version of the function call is

  (foo . (nil . nil)),
or in other words,

  (cons foo
           (cons nil
                     nil)).
So it really should be destructuring that way anyway.

Now, having said that, can anyone give a good reason that (car nil) and (cdr nil) are nil? It seems a little strange to me, although I can see that it helps destructuring.

-----


Yes, you could of course use map for the simple example in the post. I didn't want to make it more complicated than necessary for a post- If you want a more complicated example that can't be done with map, here's a function that removes pairs of identical items from a list:

  (def rem-pairs ((a . (b . c)))
      (when a
           (if (is a b) (rem-pairs c)
              (cons a (rem-pairs:cons b c)))))

  arc> (rem-pairs '(d r b s d d e w))
  (d r b s e w)
This function, also, will work in every case but break when there are nils in the list)

-----

1 point by almkglor 6499 days ago | link

For everything else, there's pattern matching (on nex-3's arc-wiki).

  (pat-match:def rem-pairs
    ( (a b . c) )
        (if (is a b)
          (rem-pairs c)
          `(,a ,@(rem-pairs `(,b ,@c))))
    ( (a) )
         `(,a)
    ( () )  ())
Possibly I can make it such that you can even say something like (a ,(b (is a b)) . c) in the pattern guard, but it seems a semi-hard problem.

  ;does not work in current version yet!!
  (pat-match:def rem-pairs
    ( (a ,(b (is a b)) . c) )
      (rem-pairs c)
    ( (a . as) )
      `(,a ,@(rem-pairs as))
    ( () )
      () )

-----

1 point by greatness 6499 days ago | link

I'm still not seeing the win of pattern matching here, I'm afraid. This is actually longer than the standard definition using car/cdr. Maybe it's better for more complicated things, I suppose, but that'll defeat the purpose because it wouldn't be legible at that point (as if it is now).

-----

1 point by almkglor 6499 days ago | link

The big win is that it's assuredly correct, and you don't have to mess around dealing with car and cdr. Crossref def varline in app.arc : arc1 had a bug there because it's ridiculously easy to make a mistake dealing with car and cdr. If you can't find the bug, try rewriting the code into pattern-matching form.

-----

1 point by greatness 6499 days ago | link

I'm not seeing the big win over something like this:

  (def print-list ((a . b))
    (when or.a.b
       prn.a
       print-list.b))

  (def rem-pairs ((a . (b . c)))
    (when or.a.b.c
      (if is.a.b rem-pairs.c
                 (cons a (rem-pairs:cons b c)))))

-----

1 point by drcode 6499 days ago | link

Well, I'd be happy with that, except it doesn't work- There's no way to know with or.a.b if you're at the end of the list or if there's just a nil as a last item in the list. Notice the missing item here:

  > (do (print-list '(nil nil nil)) 1)
  nil
  nil
  1

-----

1 point by greatness 6499 days ago | link

Ah, I see. When destructuring the arguments, if the last argument is nil it is equivalent to not being an item. ie:

  arc> (= a '(1 2 nil))
  (1 2 nil)
has a last destructuring bind of (nil . nil) so 'a would be nil and 'b would be nil, making my code not work and making it impossible to differentiate between the end of the list and the list with a last item of nil.

Even so, it's not that much of a problem:

  (def print-list (args)
    (unless no.args
       (prn:car args)
       (print-list:cdr args)))
This code shares almost the same amount of brevity, though I believe it defeats the purpose of what you were trying to do with the destructuring bind (make the calls to car/cdr disappear).

I don't believe your solution is the right thing to do because it wouldn't make sense for the car to be optional and then not force the cdr to be optional. I do not believe an optimal destructuring solution exists that could improve on the brevity of the original car/cdr solution.

-----


I noticed this contradiction, too... :) If we're not going to use c[ad]r composability, why not just use unique, easily distinguishable names for all of these that don't compose:

  car  --> hd
  cdr  --> tl
  caar --> inner
  cddr --> skip2
  cadr --> second
...or something like that. Unique names would reduce errors.

-----


Of course, going down that road makes it bulkier and starts making the brevity less convincing :)

-----

More