Arc Forumnew | comments | leaders | submitlogin
Extending + to do int plus list
1 point by alimoeeny 3143 days ago | 6 comments
Hey guys, I am trying to extend + so that I can add an int to a list (each item of the list). So far I am using lib/extend.arc and I have:

  (extend + args
          (and (isa (car args) 'int) (isa (cdr args) 'cons) (> (len (flat(cdr args))) 1))
          (map [+ _ (car args)] (flat (cdr args))))

and it works fine with 1D matrices (lists). But I want to preserve my matrix structures. Like, I want to do:

  (+ 3 '((1 2) (3 4)))
and get ((4 5 ) (6 7)) instead I get (4 5 6 7) now.

Any suggestions?



3 points by fallintothis 3143 days ago | link

This isn't exactly like your code, since I wasn't sure what you wanted it to do in the case of three or more arguments, but the important part is the alternative to map.

  (extend + (n xs . rest) (and (number n) (acons xs) (no rest))
    (treewise cons [only.orig _ n] xs))

  arc> (+ 3 '((1 2) (3 4)))
  ((4 5) (6 7))
  arc> (+ 3 '(1 2 3))
  (4 5 6)
  arc> (+ 5 '((((((5)))))))
  ((((((10))))))
  arc> (+ 3 '(1 2 3) '(4 5 6))
  Error: "+: expects type <number> as 2nd argument, given: (1 2 3 . nil); other arguments were: 3 (4 5 6 . nil)"

-----

3 points by rocketnia 3143 days ago | link

After hammering on your approach a little, here's what I get. ^_^ I like to maintain the fact that Arc's '+ is left-associative, so I don't give myself as much leeway with the additional arguments.

  ; We're going to have a meaning for number-plus-list, so we override
  ; the default number behavior, which assumes that only numbers can be
  ; added to numbers.
  (extend + args (let (a b) args (and number.a number.b))
    (let (a b . rest) args
      (apply + (do.orig a b) rest)))
  
  (extend + args (let (a b) args (and cdr.args number.a alist.b))
    (let (n xs . rest) args
      (apply + (map [+ n _] xs) rest)))
Saying (treewise cons [only.+ _ n] xs) is a bit more wordy than necessary here, but it's still a good way to accomplish (+ n xs) inline, without extending '+.

Oh, hey, if 'treewise could tell that it had a cyclic data structure, it would also be a more robust option... but that's not the case yet. Should it be?

-----

1 point by fallintothis 3143 days ago | link

I like to maintain the fact that Arc's '+ is left-associative

Good work!

if 'treewise could tell that it had a cyclic data structure, it would also be a more robust option

Do you mean cyclic structure like this?

  arc> (= xs (list 1))
  (1)
  arc> (do1 nil (= (cdr xs) xs))
  nil
  arc> (xs 1000)
  1
Never thought of that. I mean, the P part of the vanilla Arc REPL breaks on them, and I've never been compelled to use cycles. When are cyclic lists used? I guess if you're representing certain graphs?

In a more general sense, I wear my opinion about treewise on my sleeve: http://arclanguage.org/item?id=12115.

-----

2 points by garply 3142 days ago | link

I suggest you make this a method that only works on vector and matrix types.

-----

2 points by akkartik 3142 days ago | link

I don't follow. Excluding what? And why?

-----

2 points by rocketnia 3141 days ago | link

If the behavior were in a different utility named 'v+ or something, you wouldn't have a "two libraries extending the same case" conflict (just a "two libraries defining the same variable" one :-p ), and you'd also be able to have (v+ '(1 0 0) '(0 1 0)) be '(1 1 0) without conflicting with Arc's existing result of '(1 0 0 0 1 0).

Using 'extend generally also has the drawback that existing code that expects to get an error from something like (+ 1 '(1 2 3)) won't get that error anymore. This is less of a problem when using a tagged type that people are very unlikely to be using already, but numbers and lists are especially common.

For fun, here's an implementation. ^_^

  (def v+ (first . rest)
    (iflet (second . rest) rest
      (apply v+ (v+binary first second) rest)
      first))
  
  (def v+binary (a b)
    (err:+ "Can't " (tostring:write `(v+ ,a ,b))))
  
  (extend v+binary (a b) (and number.a number.b)
    (+ a b))
  
  (extend v+binary (n xs) (and number.n alist.xs)
    (map [v+ n _] xs))
  
  (extend v+binary (xs n) (and alist.xs number.n)
    (map [v+ _ n] xs))
  
  (extend v+binary (xs ys) (and alist.xs alist.ys
                             (is len.xs len.ys))
    (map v+ xs ys))
  
  (extend v+binary (xs ys) (and single.xs alist.ys (~single ys))
    (v+ car.xs ys))
  
  (extend v+binary (xs ys) (and alist.xs (~single xs) single.ys)
    (v+ xs car.ys))

  arc> (v+ '((1 0) (0 1)) '((2 0) (0 2)))
  ((3 0) (0 3))
  arc> (v+ 1 2 '(10 20) '(100 200) '(20) 1)
  (134 244)

-----