В SBCL, как можно положить лямбда-выражение в слот структуры [например, (setf (struct-slot1 struct1) '(lambda (x) (* x x)))
], чтобы его можно было вызвать с помощью funcall
или apply
? Компилятор SBCL жалуется на: wanted one of (FUNCTION SYMBOL)
. Есть ли способ установить такой лямбда, не компилируя его или не давая ему явное имя? Почему выражение лямбда не является функцией? Я хотел бы сделать что-то вроде: (funcall (function (struct-slot1 struct1)) 3)
. Спасибо за любые идеи. (ps: обычно я компилирую лямбда перед запуском, но во время отладки мне нужно видеть внутренности лямбда.)Выражения SBCL и Lambda
ответ
Это не спецификация SBCL, но в соответствии со стандартом ANSI Common Lisp.
Преобразование лямбда-выражения в виде списка в функции
Это ваши варианты:
CL-USER 168 > (funcall (coerce '(lambda (x) (* x x))
'function)
4)
16
CL-USER 169 > (funcall (compile nil '(lambda (x) (* x x)))
4)
16
CL-USER 170 > (funcall (eval '(lambda (x) (* x x))) ; because LAMBDA is a macro, too
4)
16
CL-USER 171 > (funcall (eval '(function (lambda (x) (* x x))))
4)
16
Заметим, однако, что лямбда-выражение ссылается на нулевую лексическую среду. Таким образом, он не имеет доступа к каким-либо лексическим переменным из окружающего кода.
лямбда-выражения не функционируют объекты
Почему лямбда-выражение не является функцией?
Потому что это всего лишь список, а не код. Чтобы сделать лямбда-выражение в коде, вы должны превратить его в объект функции.
Некоторые другие (часто более старые) Lisps позволяют использовать лямбда-выражения в качестве кода, но не Common Lisp. Это определяется стандартом.
Вы не можете сделать (funcall '(lambda (x) (+ x x)) 3)
. Сначала вы должны преобразовать лямбда-выражение в объект функции.
ФУНКЦИЯ является специальным оператором -> синтаксис + семантика
(FUNCALL (функция (структура-slot1 Struct1)) 3)
Это ошибка синтаксиса, уже. FUNCTION
является специальным оператором и ожидает, что имя функции или лямбда-выражение. (struct-slot1 struct1)
нет. (struct-slot1 struct1)
- это код, который извлекает значение из структуры. Но это не имя функции , которое было бы символом или списком (setf <some-symbol>)
. Это также не выражение лямбда, которое было бы чем-то вроде (lambda (...) ...)
.
Спасибо, Райнер.Я забыл о принуждении - это его решает. Также спасибо за ваше ясное объяснение, которое по моим лампам лучше, чем в Практических общих Lisp> Функции> Анонимные функции. – davypough
Нужно ли «принуждение» в первом примере? Я вижу, что 'type-of (лямбда (x) (* x x))' уже 'функция'. – agam
@agam: пример состоял в том, как получить из кода в виде списка данных допустимую функцию -> from '(quote (lambda() ...))' функции. '(lambda() ...)' уже является функцией, потому что она некорректна. –
(ps: обычно я скомбинирую лямбду перед запуском, но во время отладки мне нужно видеть внутренности лямбда.)
Попробуйте это:
(proclaim '(optimize (debug 3)))
В SBCL, вы также можете сделать это:
(sb-ext:restrict-compiler-policy 'debug 3)
... который устанавливает самую низкую допустимую политику для отладки. Документация говорит:
См. Также: ПОЛИТИКА в СО-КОМПИЛЯЦИИ.
Теперь определим простой хэш-таблицу для испытаний:
CL-USER> (defparameter *hash* (make-hash-table :test #'eq))
Вставьте анонимную функцию:
CL-USER> (setf (gethash :fun *hash*) (lambda (u) (* 10 u)))
#<FUNCTION (LAMBDA (U)) {1005140E2B}>
Называйте это плохо:
CL-USER> (funcall (gethash :fun *hash*) "oops")
отладчик показывает вверх :
Argument X is not a NUMBER: "oops"
[Condition of type SIMPLE-TYPE-ERROR]
Restarts:
0: [RETRY] Retry SLIME REPL evaluation request.
1: [*ABORT] Return to SLIME's top level.
2: [ABORT] abort thread (#<THREAD "repl-thread" RUNNING {10041C8033}>)
Backtrace:
0: (SB-KERNEL:TWO-ARG-* "oops" 10)
1: ((LAMBDA (U)) "oops")
2: (SB-INT:SIMPLE-EVAL-IN-LEXENV (FUNCALL (GETHASH :FUN *HASH*) "oops") #<NULL-LEXENV>)
3: (EVAL (FUNCALL (GETHASH :FUN *HASH*) "oops"))
Перейти к кадру # 1, ((LAMBDA (U)) "oops")
и нажмите v (А.К.А. sldb-show-source
). Новый буфер выскакивает со следующим содержанием:
(LAMBDA()
(PROGN
(LET* ((#:HASHTABLE *HASH*) (#:NEW1 (LAMBDA (U) (#:***HERE*** (* 10 U)))))
(SB-KERNEL:%PUTHASH :FUN #:HASHTABLE #:NEW1))))
Благодаря политике отладчика является достаточно высоким, исходный код анонимной функции доступен, даже если оно было напечатано в REPL. Если ваша анонимная функция будет скомпилирована из исходного файла, то нажатие v перейдет к соответствующей точке в этом файле (что соответствует форме, завернутой в вышеописанный термин ***HERE***
).
Если вы хотите, вы можете также хранить код как данные, прежде чем скомпилировать:
(defun wrap-and-compile (code)
(let ((function (compile nil code)))
(compile nil `(lambda (&rest args)
(restart-case (apply ,function args)
(DEBUG() :report ,(format nil "~S" code)
',code))))))
(setf (gethash :wrapped *hash*)
(wrap-and-compile '(lambda (x) (* 10 x))))
(funcall (gethash :wrapped *hash*) "Boo")
И отладчик показывает:
Argument X is not a NUMBER: "Boo"
[Condition of type SIMPLE-TYPE-ERROR]
Restarts:
0: [DEBUG] (LAMBDA (X) (* 10 X))
1: [RETRY] Retry SLIME interactive evaluation request.
2: [*ABORT] Return to SLIME's top level.
3: [ABORT] abort thread (#<THREAD "worker" RUNNING {100513A403}>)
Это немного Hacky, но он работает. Перезапуск DEBUG возвращает исходные данные, из которых была скомпилирована функция.
Интересно. Тем не менее, мои анонимные функции сконструированы [и, возможно, скомпилированы с (скомпилировать nil
@ davypough Просто, чтобы убедиться, что я попытался с помощью функции, подобной этой: '(compile nil (list 'lambda (list' x) (list '*' x 10)))' и это все еще работает. Но в любом случае вы можете создать свой собственный объект, который хранит функции-данные перед компиляцией. См. Править. – coredump
- 1. sbcl terminal и sbcl file
- 2. Цепочки выражения Lambda
- 3. Объяснение этого выражения Lambda
- 4. Рекурсивный запрос выражения Lambda
- 5. Динамический вызов выражения Lambda
- 6. lambda to tree выражения
- 7. Синтаксис выражения Lambda
- 8. Динамические выражения LINQ и Dynamic Lambda?
- 9. Использование выражения lambda group by и count
- 10. C#: Объединение AddRange() и выражения Lambda
- 11. Java Lambda Выражения и информация о событии
- 12. Многопоточность в SBCL
- 13. SBCL и LangUtils
- 14. Общая ошибка выражения lambda Lisp
- 15. Значение выражения lambda Значение/модификация
- 16. Lambda Calculus Сокращение/оценочные выражения
- 17. Ошибка выражения Lambda в MVC4
- 18. Преобразование выражения lambda в Json
- 19. IComparer с использованием выражения Lambda
- 20. Преобразование выражения lambda в строку
- 21. LEFT JOIN CTE как выражение выражения выражения или выражения Lambda
- 22. Нужна помощь, выполняемая нить SBCL
- 23. Получить идентификатор темы в SBCL
- 24. Lambda выражение и InvokeOperation
- 25. Получить имя метода с помощью выражения Lambda
- 26. Согласование выражения lambda C++ в шаблонах
- 27. JsonResult из выражения lambda using join
- 28. Получите класс оболочки выражения lambda Java
- 29. Использование выражения Lambda в практическом программировании
- 30. Динамическое построение выражения Linq Lambda Expression
Ваш прецедент не поясняет, читаете ли вы откуда-то или что-то. Обычно вы просто делаете '(setf (struct-slot1 struct1) (lambda (x) (* x x))). Тогда вы можете '(funcall (struct-slot1 struct1) 2) => 4' –
Извините за путаницу (но я был в замешательстве!) Я пытался сделать что-то вроде предложения с помощью setf, но мне нужно было построить выражение лямбда , поэтому он будет выглядеть примерно так: (setf (struct-slot1 struct1) '(lambda (x) (* x, (+ 2 2)))), который устанавливает список, а не функцию. Но, как замечает Райнер, вы можете превратить список в функцию с coerce [а затем вы можете получить доступ к выражению лямбда с помощью (function-lambda-list (struct-slot1 struct1)]. (Только для записи ввода записей, я обрабатывая файл спецификации пользователя с помощью некоторых макросов, которые строят эти лямбда-выражения.) – davypough
Я не уверен, что понимаю этот прецедент. Почему бы просто не просто (setf ... (let ((y (+ 2 2))) (lambda (x) (* xy)))) '? –