#ifndef в Common Lisp

В C, чтобы убедиться, что мы не включаем заголовки, которые мы включили, мы используем следующую структуру:

#ifndef UTILS
#define UTILS

#include "my_utils.h"

#endif

Я разбил свою программу на Лиспе на отдельные файлы; несколько файлов иногда используют один и тот же файл (например, my_utilities используется несколькими файлами). Когда я запускаю программу, я получаю предупреждения о том, что я переопределяю load одного и того же файла несколько раз).

Это можно исправить, выполнив что-то похожее на #ifndef в C. Что такое эквивалентный или стандартный метод Common Lisp для этого?

Я довольно новичок в Лиспе. Дайте мне знать, если есть лучшие практики (возможно, другой метод структурирования моих программ?), Которые мне не хватает.

2 ответа

Решение

Вопрос, который вы задали

Прямой аналог препроцессорных условий типа #if в C это #+ средство условного считывания во время чтения.

Вопрос, который вы хотели задать

Чтобы избежать многократной загрузки файла, вы можете использовать стандарт (но не рекомендуется) provide / require средство, или дополнительная система как ASDF.

  1. Для приложений и библиотек Common Lisp предпочтительно использовать инструмент управления системой. Как ASDF или что-то еще, что может обеспечить ваша реализация Система - это набор файлов с зависимостями и различными действиями (загрузка, компиляция,...).

  2. Вы всегда можете проверить состояние среды выполнения и что-то сделать.

Пример:

(unless (fboundp 'foobar)
  (require "foo")
  (load "bar"))

(unless (find-package 'foobar)
  (require "foo")
  (load "bar"))
  1. PROVIDE а также REQUIRE встроенные функции именно для этого. Если вам нужен модуль, он будет загружен, если уже provided, К сожалению, эта функциональность недостаточно указана в стандарте, но реализации могут предоставлять полезную функциональность.

  2. Стандартные среды выполнения Lisp имеют список функций в списке *features*, Вы можете использовать это для рекламы и проверки функциональности.

Пример:

В вашей библиотеке:

(push :cool-new-graphics-library cl:*features*)

В вашем коде приложения:

(when (member :cool-new-graphics-library cl:*features*)
  (funcall (find-symbol "DRAW-SPACE-SHIP" "CNGL")
           :death-star))

Common Lisp предоставляет способ обусловить время чтения. Следующий код будет прочитан только когда :cool-new-graphics-library функция присутствует, и, следовательно, только тогда она будет выполнена позже:

#+cool-new-graphics-library(cngl:draw-space-ship :death-star)

Common Lisp также позволяет вам выразить некоторую логику:

#+(and lispworks cool-new-graphics-library)
  (cngl:draw-space-ship :enterprise)

#-cool-new-graphics-library(warn "no cool graphics library available")

Обратите внимание, что вы можете заставить Lisp выполнять код во время компиляции:

(eval-when (:load-toplevel :compile-toplevel :execute)
  #+(and lispworks cool-new-graphics-library)
    (cngl:draw-space-ship :enterprise)

  #-cool-new-graphics-library(warn "no cool graphics library available")
 )

Для этого работать EVAL-WHEN должен быть на верхнем уровне в файле. Это означает, что он не будет работать глубоко во вложенных формах. Это работает внутри верхнего уровня PROGN,LOCALLY, MACROLET а также SYMBOL-MACROLET, хоть.

таким образом EVAL-WHEN позволяет запускать код, который является частью файла, который в данный момент компилируется. Этот код, чем может искать загруженные системы, предоставленные модули, доступные функции и многое другое.

Другие вопросы по тегам