schemeracket

Combination of list-ref and index-of in racket


(define code 
  '(
    function f1 < a b >
    vars x y
    begin
      "..."
    end
  )
)

(define ,(cadr code) '()) ;first method

(define ,(list-ref code (+ (index-of code 'function) 1)) '()) ;second method

Why does the second method give the warning "define: not an identifier, identifier with default, or keyword for procedure argument" even though both ,(cadr code) and ,(list-ref code (+ (index-of code 'function) 1)) return f1?


Solution

  • The program is read, expanded and then evaluated. The unquote (,) syntax is handled by the reader. This means, that when you write:

    (define ,(cadr code) '())
    

    in you program, it is equivalent to writing:

    (define (unquote (cadr code)) '())
    

    Which we can write as:

    (define (unquote [cadr code]) 
       '())
    

    So here you define a function named unquote that takes one optional argument named cadr. The default argument for cadr is code.

    Now you write:

    (define ,(list-ref code (+ (index-of code 'function) 1)) '()) 
    

    which the reader turns into:

    (define (unquote (list-ref code (+ (index-of code 'function) 1)))
         '()) 
    

    We see here that (list-ref code (+ (index-of code 'function) 1)) is highlighted with the error:

    define: not an identifier, identifier with default, or keyword for procedure argument in:

    This meant that define expected an indentifier, or [identifier default] or an #: keyword.

    If we check the grammar, we see:

    (λ kw-formals body ...+)
    
     
    kw-formals =  (arg ...)
               |  (arg ...+ . rest-id)
               |  rest-id
    
    arg = id
        | [id default-expr]
        | keyword id
        | keyword [id default-expr]
    

    So the error message just means that whatever follows the name of a function needs to be one of the four case in the grammar for arg.

    Note: The unquote character , is meant to be used inside a quasiquote (a backtick) [look unquote up in the docs].