2016-11-28 7 views
3

Я получу неопределенное предупреждение о функции f2 в SBCL со следующим примером кода. Возможно ли, что я могу сначала объявить f2, как и в C, чтобы избежать предупреждения. I Googled, без всякой подсказки.Как объявить функцию перед ее определением в общем lisp?

(defun f() 
    (print (f2))) 

(defun f2() 
    (print "f2")) 

ответ

5

Если вы используете функцию, прежде чем определить его в одном compilation unit, например, тот же файл, то компилятор не жалуются на неопределенной функции (обычная load все еще может, поэтому компилировать код первого !)

В противном случае, вы можете declaimftype:

(declaim (ftype (function() t) f2) 

означает, что f2 не принимает никаких аргументов и возвращает один value типа t.

Однако имеет смысл скомпилировать файл, в котором вы используете эту функцию, пока определение уже загружено. Вы можете (и должны!) Использовать asdf как Lisp-specific make(1): задавать зависимости, чтобы компилятор имел определения всех функций при компиляции своих пользователей.

+0

Очень ценный, я искал это в течение очень долгого времени. ;-) И это работает с декламацией. - Кстати, даже я поставил обе функции в один и тот же файл, sbcl по-прежнему дает неопределенное предупреждение о функции. –

+1

@lll Возможно, вы просто загрузили файл, а не сначала его компилировали. Из repl используйте '(load (compile-file" file.lisp "))', или из Slime/Sly используйте 'C-c C-k'. – jkiiski

+0

На самом деле я думаю, что блок компиляции стандартных вызовов не влияет на семантику компиляции. Семантика компилятора функции в файле, которая используется до того, как она будет определена в том же файле, не имеет ничего общего с «единицей компиляции» - она ​​просто связана с идеей компиляции файлов, а не с концепцией «единицы компиляции» '- которые существуют только неопределенно, определяемые с помощью единицы компиляции. –

1

Просто измените порядок вашей defun's. Сначала определим f2 и f.

+0

Невозможно использовать этот подход, если у вас есть взаимная рекурсия, которая создает цикл в графе вызовов. – Kaz

+0

Я понимаю, спасибо за разъяснения. –

+0

Хотя, определения, используемые затем, являются хорошей организацией программы. Трудно поддерживать в течение длительного времени в больших программах, хотя и не перемещая функции вокруг, что создает уродливые текстовые различия, которые мешают слияниям. Часто вы находите: «Черт, мне нужно вызвать эту функцию отсюда сейчас, но это определено позже». – Kaz

4

Если функции находятся в одном файле, компилятор не выдаст предупреждение.

Пример SBCL:

bash-3.2$ sbcl 
This is SBCL 1.3.10, an implementation of ANSI Common Lisp. 
More information about SBCL is available at <http://www.sbcl.org/>. 

SBCL is free software, provided as is, with absolutely no warranty. 
It is mostly in the public domain; some portions are provided under 
BSD-style licenses. See the CREDITS and COPYING files in the 
distribution for more information. 
* (compile-file "/tmp/order.lisp") 

; compiling file "/private/tmp/order.lisp" (written 28 NOV 2016 12:14:37 PM): 
; compiling (DEFUN F ...) 
; compiling (DEFUN F2 ...) 

; /tmp/order.fasl written 
; compilation finished in 0:00:00.178 
#P"/private/tmp/order.fasl" 
NIL 
NIL 
* (load *) 

T 
* 
3

Вы не должны поместить функции в тот же файл в Common Lisp для них, чтобы быть в одной и той же единице компиляции.

Выполнение этого анти-шаблона; большие программы, конечно, построены из модулей, большинство из которых вызывают функции, которые находятся в другом модуле. Вы не можете перевернуть всю программу в один физический модуль, чтобы избежать предупреждения об этом.

Лисп имеет механизм, с помощью которого кластер компилирует рассматривается как единое целое обобщение: with-compilation-unit макрос:

(with-compilation-unit 
    (compile-file "file-f") 
    (compile-file "file-f2")) 

Если вы используете систему ASDF сборки, я припоминаю, что делает with-compilation-unit под капот для вас, вокруг всех файлов системы.

Этот подход поможет устранить те предупреждения, которые отложены. То есть, если реализация предупреждает о неопределенных идентификаторах, но откладывает до конца блока компиляции, тогда, если вы используете этот макрос, отсрочка расширяется до конца полного блока компиляции, охватывающего несколько файлов.

Когда предупреждения о неопределенных идентификаторах отложены, цель состоит в том, чтобы устранить эти предупреждения. Если определение ранее не заданной функции появляется до конца блока перевода, предупреждение может быть подавлено. Этот макрос позволяет определять в одном файле подавление отложенного предупреждения в другом файле.

Если реализация не откладывает предупреждения, макрос не поможет.

+0

Это просто отменяет предупреждение до конца блока компиляции. Вопрос состоял в том, чтобы избавиться от предупреждения. –

+0

Если вы немного об этом подумали, похоже, что было бы неплохо избавиться от предупреждения, просто обернув СО-КОМПИЛЯЦИОННЫЙ ЕДИНИЦ вокруг компиляции двух файлов. Функция будет по-прежнему не определена в первом файле. –

+0

@RainerJoswig Я не знаю об ANSI CL, чтобы сказать «пожалуйста, избавитесь от этого предупреждения». Идея состоит в том, что **, если реализация отбрасывает предупреждения **, то 'with-compilation-unit' будет расширять эту отсрочку по нескольким файлам. Реализация отбрасывает предупреждения точно для того, чтобы сбить ненужные. Отсроченное предупреждение «неопределенной функции» самопроизвольно исчезает, если определение функции видно до конца блока компиляции. – Kaz

 Смежные вопросы

  • Нет связанных вопросов^_^