Arc Forumnew | comments | leaders | submitlogin
How do you concatenate two lists in Arc?
3 points by lark 3805 days ago | 5 comments
Is there a built-in function in Arc for concatenating two lists? There doesn't seem to be an append function available.

I know you can add two lists with the + operator like shown below, but reading that makes me think I'm doing math, which is confusing when reading the code again.

   (+ (list 1 2 3) (list 4 5 6))
You are welcome to laugh about this.

Is there also a function for adding two hash tables? + doesn't work for that.



3 points by zck 3804 days ago | link

To repeat my comments from earlier (http://arclanguage.org/item?id=17074), calling 'join on lists is not quite the same as calling '+ on the same lists. The results are 'iso to each other, but not 'is .

  arc> (= l (list 1 2))
  (1 2)
  arc> (+ l)
  (1 2)
  arc> (join l)
  (1 2)
  arc> (is (+ l) (join l))
  nil
  arc> (iso (+ l) (join l))
  t
More confusingly, it also changes the cons cells inside the lists:

  arc> (= l (list (list 1)))
  ((1))
  arc> (is (car (+ l)) (car (join l)))
  nil
  arc> (iso (car (+ l)) (car (join l)))
  t
>Is there also a function for adding two hash tables?

Hash tables are missing a lot of helper functions, yes. There's no built-in way (that I know of) of combining them, although writing one isn't hard -- you just have to decide what to do about collisions. I just took a few minutes and wrote one up. I deal with collisions by letting the earlier hash win. My code:

  (def join-tables tables
       (if (no tables)
           (obj)
         (let rest (apply join-tables (cdr tables))
              (each (key value) (car tables)
                    (= rest.key
                       value))
              rest)))
Unit tests for this code:

  (suite join-tables
         empty (assert-same (join-tables)
                            (obj))
         one-table (assert-same (join-tables (obj 1 2))
                                (obj 1 2))
         two-tables (assert-same (join-tables (obj 1 2) (obj 2 3))
                                 (obj 1 2 2 3))
         multiple-values (assert-same (join-tables (obj 1 2 2 3)
                                                   (obj 3 4 4 5))
                                      (obj 1 2 2 3 3 4 4 5))
         three-tables (assert-same (join-tables (obj 1 2)
                                                (obj 2 3)
                                                (obj 3 4))
                                   (obj 1 2 2 3 3 4))
         overrides-values (assert-same (join-tables (obj 1 2)
                                                    (obj 2 3)
                                                    (obj 3 4)
                                                    (obj 1 0))
                                       (obj (1 2 2 3 3 4))))
Note: somehow, I broke 'assert-same. Not sure why. I'll fix it later today; I don't have the time right now to make sure it's done properly. If you pull the default branch of my repo, and these tests don't work, bug me until I fix it.

There's also no built-in way of telling whether they're 'iso, but I wrote one (https://bitbucket.org/zck/unit-test.arc/src/5d576dea18709cf7...) as part of my unit test framework, which is LGPL'd. Please use it and let me know what you think.

-----

3 points by zck 3804 days ago | link

Ok, fixed the broken part of unit-test.arc which wouldn't let `assert-same work on hash tables. (Commit: https://bitbucket.org/zck/unit-test.arc/commits/f3f10c942861...)

Of course, one unit tests above was also broken. The fixed unit test suite:

    (suite join-tables
            empty (assert-same (join-tables)
                               (obj))
            one-table (assert-same (join-tables (obj 1 2))
                                   (obj 1 2))
            two-tables (assert-same (join-tables (obj 1 2) (obj 2 3))
                                    (obj 1 2 2 3))
            multiple-values (assert-same (join-tables (obj 1 2 2 3)
                                                      (obj 3 4 4 5))
                                         (obj 1 2 2 3 3 4 4 5))
            three-tables (assert-same (join-tables (obj 1 2)
                                                   (obj 2 3)
                                                   (obj 3 4))
                                      (obj 1 2 2 3 3 4))
            overrides-values (assert-same (join-tables (obj 1 2)
                                                       (obj 2 3)
                                                       (obj 3 4)
                                                       (obj 1 0))
                                          (obj 1 2 2 3 3 4)))
Thanks for the opportunity to find this bug!

-----

2 points by zck 3804 days ago | link

Ugh, I'm past the edit time. Of course one wouldn't expect `(is (+ l) (join l))` to be 't, because that's the definition of 'is. (even `(is (list 1) (list 1))` returns 'nil). But the second part is bad, I think: the elements inside l should stay the same.

I blame not really hacking in Arc much lately. I haven't really been up for programming much of anything.

-----

3 points by rocketnia 3804 days ago | link

"But the second part is bad, I think: the elements inside l should stay the same."

I agree. I really think this is a simple coding mistake in ac.scm. I talk more about this here, a reply to that thread you linked to: http://arclanguage.org/item?id=17114

I completely forgot about this difference between + and 'join after that thread, and I don't remember encountering it before that either. How fitting it's a testing framework that brings this bug to the surface! :-p

-----

3 points by rocketnia 3805 days ago | link

There's actually another function, 'join, that just appends lists.

  (join (list 1 2 3) (list 4 5 6))
A while back, fallintothis and akkartik talked about this a little: http://arclanguage.org/item?id=11104 (Look for "prefers" and "over time" on the page.)

-----