Szukaj…


Higieniczne i referencyjnie przezroczyste makra z regułami składni

Największą przewagą LISP i Scheme nad innym głównym językiem programowania jest ich system makr. W przeciwieństwie do preprocesora C i innych języków makr, makra Schematu pobierają analizowany kod jako dane wejściowe i zwracają kod rozszerzony jako dane wyjściowe. Jest to jedna z aplikacji wyrażenia Schemat „kod to dane” i to czyni język tak potężnym.

Makra w schemacie są tworzone przy użyciu define-syntax , która może definiować makro na wiele sposobów. Najprostszą metodą jest użycie syntax-rules , które wykorzystują dopasowanie wzorca do przekształcenia kodu wejściowego w kod wyjściowy.

W tym przykładzie utworzono prostą składnię dla for item in list i for list as item składni for list as item do zapętlania elementów na liście:

(define-syntax for
  (syntax-rules (in as) ; 'in' and 'as' keywords must match in the pattern
    ; When the 'for' macro is called, try matching this pattern
    ((for element in list
          body ...) ; Match one or more body expressions
     ; Transform the input code
     (for-each (lambda (element)
                 body ...)
               list))
    ; Try matching another pattern if the first fails
    ((for list as element
          body ...)
     ; Use the existing macro for the transform
     (for element in list
          body ...))))

Te dwa makra mogą być następnie używane w następujący sposób, zapewniając bardziej imperatywny styl:

(let ((names '(Alice Bob Eve)))
  (for name in names
    (display "Hello ")
    (display name)
    (newline))
  (for names as name
    (display "name: ")
    (display name)
    (newline)))

Uruchomienie kodu zapewni oczekiwany wynik:

Hello Alice
Hello Bob
Hello Eve
name: Alice
name: Bob
name: Eve

Najczęstszym błędem, na który należy zwrócić uwagę, jest nieprzekazanie poprawnych wartości do makra, co często skutkuje nieprzydatnym komunikatem o błędzie, który dotyczy rozszerzonej formy zamiast wywołania makra.

Powyższe definicje składni for nie sprawdzają, czy przekazano im identyfikator i listę, więc przekazanie dowolnego innego typu spowoduje błąd wskazujący na wywołanie for-each zamiast wywołania for . Debugowanie tego przeczy celowi makra, więc to użytkownik musi wprowadzić tam kontrole i zgłosić błędy użytkowania, które następnie można wykryć podczas kompilacji.



Modified text is an extract of the original Stack Overflow Documentation
Licencjonowany na podstawie CC BY-SA 3.0
Nie związany z Stack Overflow