Arc Forumnew | comments | leaders | submitlogin
Rewriting in to accept a list?
2 points by bh 3696 days ago | 4 comments
You know how in checks the first parameter to see if it matches any of the rest? I wanted a version that would check the first parameter against a list, so I tried to write one

    arc> (mac inl (elt lst)
           `(in ,elt ,@lst))
    #(tagged mac #<procedure: inl>)
    arc> (inl 1 '(1 2 3))
    _quote: undefined;
     cannot reference undefined identifier
and have no clue why this is happening.

Sorry, I know this isn't Stack Overflow, but virtually no one follows the arc-lisp tag there, and I don't know anywhere else to post.



2 points by zck 3696 days ago | link

>Sorry, I know this isn't Stack Overflow, but virtually no one follows the arc-lisp tag there, and I don't know anywhere else to post.

Don't worry about this. I'm happy whenever anyone's talking about Arc. I'd love to have the problem that people are posting too much here.

I've been confused by this issue too. There are two things here.

1. First, instead of using 'in, you can use 'pos:

    arc> (pos 1 '(1 2 3))
    0
2. Let's make your macro work anyway:

First, reproduce:

    arc> (inl 1 '(1 2 3))
    Error: "_quote: undefined;\n cannot reference undefined identifier"
Huh, it works if you use 'list:

    arc> (inl 1 (list 1 2 3))
    t
Or without 'list:

    arc> (inl 1 (1 2 3))
    t
This is interesting. Let's use 'macex1 to see what happens:

    arc> (macex1 '(inl 1 '(1 2 3)))
    (in 1 quote (1 2 3))
So the problem is that '(1 2 3) really is a list with two things in it: the symbol 'quote and the list (1 2 3). I'm a little bit uncomfortable with this explanation, but this seems to mean that you don't want to pass a quoted list into a macro, but unquoted. This is the way most macros are used, but I hesitate to make it a global rule. Some day I'll understand macros better.

-----

1 point by akkartik 3696 days ago | link

  arc> (inl 1 (list 1 2 3))
  t
I wouldn't rely on that:

  arc> (inl list (list 1 2 3))
  t
  arc> (let x list
         (prn list)
         (inl list (list 1 2 3 4)))
  #<procedure: list>
  t
So you're actually searching a list that includes the function list.

"..you don't want to pass a quoted list into a macro, but unquoted. This is the way most macros are used, but I hesitate to make it a global rule."

The rule is, the arg is eval'd if it's eval'd in the expansion. (Since macros don't eval args, they eval the return value.)

  (mac foo (x) (cons 3 ,x))  ; will eval x
  (mac bar (x) (cons 3 ',x))  ; won't eval x

-----

2 points by akkartik 3696 days ago | link

You can see what your macro expands to:

  arc> (macex1 '(inl 1 '(1 2 3)))
  (in 1 quote (1 2 3))
That probably explains the error message. (Quotes expand to the symbol quote.)

So all you have to do is not quote your argument:

  arc> (inl 1 (1 2 3))
  t
As a general rule, however, try not to use a macro unless you have to. In this case there's a pure function that does what you want:

  arc> (pos 1 '(1 2 3))
  0
  arc> (pos 4 '(1 2 3))
  nil
(You can use pos in a conditional just like inl because it is guaranteed to only return nil if and only if the element doesn't exist.)

More info: http://arclanguage.github.io/ref/list.html#pos. As an exercise try implementing pos for yourself :) And feel free to ask us more questions! I hadn't realized there were questions at stack overflow. I'll try to hang out there, but there's really nothing off-topic here.

-----

3 points by shader 3696 days ago | link

I think it might help to point out how the macro expands there:

  (inl 1 '(1 2 3))
is transformed by the reader to

  (inl 1 (quote (1 2 3)))
which is then macro expanded by

  `(in ,elt ,@lst)
where elt is bound to '1, and lst is bound to '(quote (1 2 3)). This means that when lst is spliced in, you get:

  '(in 1 quote (1 2 3))
As stated, the problem is largely the choice of macro instead of function. Macros are primarily useful to control evaluation; they do not evaluate their arguments by default. A macro will only let you work with the literal input, not their values. You can't (with arc) have your cake and eat it too; you can only work with either the syntax, or the values. You wouldn't be able to do something like:

  (let x '(1 2 3)
     (inl 1 x))
for instance, because it would attempt to treat the symbol 'x as if it were a list to be spliced, not the value of x. That's why you need a function, like pos.

-----