Arc Forumnew | comments | leaders | submitlogin
3 points by rocketnia 2920 days ago | link | parent

The reason = doesn't work is that

  (aget x!first)
expands to

  (if nil (cadr ...) (withs ...))
and I guess = doesn't support assigning to an 'if expression. (I wonder if it could....)

Instead of expanding into (if ...), aget could instead expand only into (cadr (assoc ...)), doing its 'if logic at expansion time. Here's a version that does that:

  (mac aget (al (o key nil))
    (if key            (= al (list al key))
        (isa al 'sym)  (= al (ssexpand al)))
    ; At this point, "al" means "arg list" rather than "assoc list." ;)
    (if (~and (alist al) (is 2 len.al)) (err "Invalid arguments to aget"))
    (let (al key) al
      `(cadr (assoc ,key ,al))))
And here's a light demonstration:

  arc> (= foo '((a 1) (b 2)))
  ((a 1) (b 2))
  arc> (aget foo 'b)
  2
  arc> (aget foo!b)
  2
  arc> (= (aget foo 'b) 3)
  3
  arc> foo
  ((a 1) (b 3))
  arc> (= (aget foo!b) 4)
  4
  arc> foo
  ((a 1) (b 4))


3 points by rocketnia 2919 days ago | link

Whoops, at http://arclanguage.org/item?id=10788 aw brought up something I overlooked: adding new keys.

Here's an imperfect correction. It's the best I can think of without resorting to the power of hacking arc.arc and stuff.

  (mac aget (al (o key nil))
    (if key            (= al (list al key))
        (isa al 'sym)  (= al (ssexpand al)))
    ; At this point, "al" means "arg list" rather than "assoc list." ;)
    (if (~and (alist al) (is 2 len.al)) (err "Invalid arguments to aget"))
    (let (al key) al
      `(alref ,al ,key)))

  ; Because of technical difficulties (specifically, that al is already a value
  ; rather than a place at this point), this can't insert new entries at the
  ; beginning of al; they'd fall right back off, since the caller's variable (or
  ; other reference) is still bound to the "old" first spot, which is oblivious
  ; to anything before it. Instead, this works by inserting new entries at the
  ; *second* spot in al. On a related note, this can't modify anything about an
  ; empty assoc list, since an empty assoc list is nil, which is immutable.
  (defset alref (al key)
    (w/uniq (g-al g-key)
      `(,(list g-al al g-key key)
        (alref ,g-al ,g-key)
        (fn (val)
          (iflet entry (assoc ,g-key ,g-al)
            (= (cadr entry) val)
              ,g-al
            (push (list ,g-key val) (cdr ,g-al))
            (err "Can't set a value in an empty assoc list, sorry."))
          val))))

-----