Arc Forumnew | comments | leaders | submitlogin
4 points by fallintothis 5377 days ago | link | parent

I can't help but feel this is the wrong way to approach the problem. Even if you got your current definition working, there are too many ways for it to break. e.g.,

  (isdef (table [for i 1 3 (= _.i (* i i))]))
reads in as

  (isdef (table (fn (_) (for i 1 3 (= _.i (* i i))))))
and fails. There's the special form fn (neither lexically nor globally bound), plus the tricky business of checking defined when compiling fn so that _ is actually lexically bound (otherwise, it appears to be undefined). Same goes for expanding the for macro and i, I imagine.

All this parsing / partial compilation smacks of over-engineering. Even if you avoid multiple-evaluation issues, it seems too easy to make a typo in the middle of a contextual each like

  (myeach (table [for i 1 3 (= _.i (* i u))])
    (prn _))
where u is undefined, meaning it tries to destructure the table expression against (prn _), leading to confusing errors:

  arc> (each (table [for i 1 3 (= _.i (* i u))]) (prn _))
  Error: "Can't understand fn arg list 1"
The syntax for this each you're trying to write is suspect. From a certain angle, it almost seems like trying to overload on arity even though both forms take an unlimited number of values (on account of the rest parameters).

For all I know about Perl (which isn't much), it looks like its foreach works with explicit and implicit variables because you can consistently parse it -- you always have parentheses delimiting the array.

  foreach $item (@items) { print $item; }
vs

  foreach (@items) { print $_; }
If that's the case, the equivalent doesn't map cleanly over to Arc, since the syntax for

  (each item items (prn item))
looks effectively the same as

  (each items (prn _))
to the parser.

I know it's probably not what you want, but perhaps you could consider something with a more regular syntax?

  (mac myeach ((var expr) . body)
    (when (no expr)
      (= expr var var '_))
    `(each ,var ,expr ,@body))

  arc> (myeach ('(1 2 3)) (prn _))
  1
  2
  3
  nil
  arc> (myeach (v '(1 2 3)) (prn v))
  1
  2
  3
  nil
  arc> (myeach ((k v) '((a 1) (b 2) (c 3))) (prn k ": " v))
  a: 1
  b: 2
  c: 3
  nil
  arc> (myeach ((k v) (table [for i 1 3 (= _.i (* i i))])) (prn k ": " v))
  2: 4
  1: 1
  3: 9
  #hash((3 . 9) (1 . 1) (2 . 4))
  arc> (myeach ((table [for i 1 3 (= _.i (* i i))])) (prn _))
  (2 4)
  (1 1)
  (3 9)
  #hash((3 . 9) (1 . 1) (2 . 4))
  arc> (macex1 '(myeach (a b) c))
  (each a b c)
  arc> (macex1 '(myeach (a) b c))
  (each _ a b c)
  arc> (let v 2 (myeach (v '(1 2 3)) (prn v)))
  1
  2
  3
  nil
  arc> (let lst '(1 2 3) (myeach (lst) (prn _)))
  1
  2
  3
  nil
The extra parentheses are kind of ugly when you have expressions (e.g., a call to table), but I find that I'm most often iterating over variables anyways. Or you could rely on the Scheme reader recognizing curly-braces as parens:

  arc> (myeach {x (range 1 5)} (prn x))
  1
  2
  3
  4
  5
  nil
Sorry I don't have any better suggestions.


1 point by palsecam 5377 days ago | link

> too many ways for it to break

> The syntax for this each you're trying to write is suspect

> perhaps you could consider something with a more regular syntax?

You're right. The more I think about it, the less I like this 'each idea.

> All this parsing / partial compilation smacks of over-engineering.

True, but this is also part of the fun here ;-)

> For all I know about Perl (which isn't much), it looks like its foreach works with explicit and implicit variables because you can consistently parse it -- you always have parentheses delimiting the array.

You are absolutely right here, and you made me realize I am actually trying to get something more dirty/complicated than in Perl, which is... really not a good sign :-D!

> Or you could rely on the Scheme reader recognizing curly-braces as parens

This is also an interesting option. Good to know.

> Sorry I don't have any better suggestions.

Gosh, that's already a bunch of good ideas! Thanks!

-----