Arc Forumnew | comments | leaders | submitlogin
1 point by alimoeeny 5150 days ago | link | parent

Any ideas why this doesn't work: (def s (x y) ( (= mx (avg x)) (= my (avg y)) (reduce + (map * (map [- _ mx] x) (map [- _ my] y)))))


4 points by fallintothis 5150 days ago | link

For one, you have an extra set of parentheses around the body of the function. Parenthetical expressions like

  (expr1 expr2 expr3 ...)
by default will evaluate expr1 and try to call it with the arguments expr2, expr3, .... E.g.,

  arc> (+ 1 2 3)
  6
This sort of rule applies recursively, so

  ((if (> 1 2) - +) 1 2 3)
first evaluates

  (if (> 1 2) - +)
which returns the function + (since (> 1 2) is false), meaning the original evaluates to

  (+ 1 2 3)
There are a few places where parenthetical expressions don't evaluate this way, but they're usually pretty obvious -- like the argument list in a def. For more details, the tutorial is a decent place to start learning about Arc & Lisp programming: http://ycombinator.com/arc/tut.txt.

To fix your code immediately, you'd just need to get rid of the extra parens. Expressions in the body of a function evaluate one after the other, returning the value of the last expression, so given

  (def f (x)
    (+ x 1)
    (+ x 2))
a call to f will calculate (+ x 1) and (+ x 2), returning the latter.

But you should (generally) only use = for global variables. For local ones, you'll want with or let.

  arc> (let x 1 (+ x 1))
  2
  arc> (with (x 1 y 2) (+ x y))
  3
So, the function

  (def s (x y)
    (with (mx (avg x) my (avg y))
      (reduce + (map *
                     (map [- _ mx] x)
                     (map [- _ my] y)))))
should do what you want. You could still perform some "map fusion". Roughly speaking,

  (map f (map g xs))
is equivalent to

  (map [f (g _)] xs)
and you save on doing multiple passes through your lists. Thus,

  (def s (xs ys)
    (with (mx (avg xs) my (avg ys))
      (reduce + (map (fn (x y) (* (- x mx) (- y my)))
                     xs
                     ys))))
is arguably cleaner, though the two-argument function does clutter stuff up a bit.

You can also write the same "destructive" style of code in Arc, though it's normally frowned upon.

  (def s (x y)
    (let xy 0
      (for i 0 (- (min (len x) (len y)) 1)
        (++ xy (* (- (x i) (avg x))
                  (- (y i) (avg y)))))
      xy))
Finally, to format code,

  put a blank line, then at least two spaces before the line of code
  (similarly for subsequent lines)
See http://arclanguage.org/formatdoc for details.

-----

2 points by alimoeeny 5150 days ago | link

Thanks a lot, that was great help, I never felt so excited about coding in a new language since Commodore 64's BASIC!

-----