Arc Forumnew | comments | leaders | submitlogin
1 point by tokipin 5894 days ago | link | parent

i see your point about it mimicking function application, and that seems to me the reason if there was any for why that order was chosen

> I find (map xs -) to be far less readable than (map - xs), not to mention (map xs ys +) vs. (map + xs ys)

well, if the function is named, the order isn't as significant. i personally don't see a difference in either of those pairs, but compare (map + xs ys) to a version where + is a lambda, and likewise with (map xs ys +)

i wonder which usage is more common: map with a named function, or map with a lambda. i'm sure it is the lambda usage, but i haven't programmed much in lisp. it would be interesting to analyze some code and see some numbers

  (map betas gammas
      [foo (bar _)
           (frob nitz)
           (xyzzy (quux _ _)
                  alpha)])

  (map betas gammas (fn (a b)
      (foo (bar a)
           (frob nitz)
           (xyzzy (quux b a)
                  alpha))))
also, it could be made to accept any order. though i don't see a reason for that besides serving as a model for other functions w/ respect to the implied underscore notation


1 point by absz 5894 days ago | link

Clearly, readability is largely personal preference. As I said, I like the syntax of your version for lengthy anonymous functions. But I don't see it as a huge net win. It might, on the other hand, be nice to have a mapover macro which turned

  (mapover as bs ... ys zs (a b ... y z)
    (do-stuff a b ... y z))
into

  (map (fn (a b ... y z) (do-stuff a b ... y z))
       as bs ... ys zs)
which might be clearer in the really-lengthy-function case. Here it is (lightly tested):

  (mac mapover (arg1 arg2 arg3 . arg4+)
    " The last two arguments to mapover are treated as the parameter list and body
      of a function `f', which is then applied to each element of the given
      sequences (the other, previous arguments) in turn; a list consisting of the
      results of this function is returned.  In short, this is equivalent to
      (map f arg1 arg2 ... argN), where `f' is the aforementioned constructed
      function.
      Note that there is *not* an implicit `do' around the body of the function;
      if there were, it would be impossible to tell where the lists ended and the
      function began.
      See also [[map]] [[each]]. "
    (withs (args  (apply   list arg1 arg2 arg3 arg4+)
            body  (last    args)
            parms (car:cut args -2 -1) ; 2nd to last
            lists (cut     args  0 -2))
      `(map (fn ,parms ,body) ,@lists)))
Note that it's limited in that there is no implicit do around the body of the function; since it can take any number of lists, there would be no way to tell where they stopped and the function began. Also note that this may well rely on the Anarki, but I'm not 100% sure if it does.

(And I'm sure someone will tell me that CL's loop can do this in 3... 2... 1...)

Overall, I do think that (map f xs) is cleaner in the named-, short-, and moderately-long-function cases, but it's always possible to write an inversion if you think differently. But what do you think of mapover as another approach?

-----

1 point by tokipin 5894 days ago | link

i wouldn't mind that, though it would probably be considered repetitive with map, and the first thing i would do would be (= map mapover) [edit]oops, macros aren't first class... yet

ya'll confuse me wit dem macros @_@. i made my own function called nap (the other option was pam, which rolls off the tongue with an undesirable cooking-spray sort of feel)

  (def nap args
       (apply map (car (rem acons args)) (keep acons args)))
i'm not exactly sure if it works as it should but it seems ok. i noticed a nifty application of this any-order form:

  arc> (nap '(1 2 3) < '(3 2 1))
  (t nil nil)

-----

2 points by absz 5894 days ago | link

Note that mapover is less general than map. It's explicitly designed for the "long anonymous function" case, so you cannot do

  (mapover '(1 2 3) '(4 5 6) +)
; instead, you must do

  (mapover '(1 2 3) '(4 5 6) (x y)
    (+ x y))
. This is why it is a macro: it needs to treat its last two arguments as part of a function body, so it cannot evaluate them. As a macro, it can package them up and put them in a function, which can be passed to map along with the lists.

nap is a clever function, but will oddly allow you to write (map '(1 2 3) < > '(4 5 6)), which is meaningless. Nevertheless, It's not a terrible idea.

-----