LISP - Передача компонента структуры, а не значения компонента - PullRequest
0 голосов
/ 14 октября 2018

У меня проблема с передачей компонентов структуры в LISP.Я хочу передать компонент, а не его значение.

Чтобы проиллюстрировать мою цель, допустим, у меня есть экземпляр структуры node.Узел содержит компоненты farmer, fox, goose и straw.Мне бы хотелось, чтобы функция была гибкой, чтобы я мог передать любой из этих компонентов в функцию.

(defun pass-comp (node object)
  (setf object 1)
  node)

(pass-comp (node (node-fox node))
(write (node-fox node))
—> 1

Ответы [ 2 ]

0 голосов
/ 14 октября 2018

Структуры в стандартном CL очень статичны - например, эффекты переопределения структуры не определены.Также не определено, можем ли мы получить доступ к структуре по имени слота.Существуют функции чтения слотов и поддержка их использования с setf.

Допустим, у нас есть тип структуры:

(defstruct node fox)

Тогда, когда мы захотим изменить компонент структурынам нужно передать функцию, которая устанавливает этот компонент:

(defun pass-comp (node setter-fn)
  (funcall setter-fn node 1)
  node)

Затем мы можем передать функцию установки:

(let ((my-node (make-node)))
  (pass-comp my-node
             (lambda (node new)
               (setf (node-fox node) new)))
  (node-fox my-node))
0 голосов
/ 14 октября 2018

В Лиспе все аргументы всегда передаются по значению.Если вы хотите изменить содержимое структуры, которую вы передаете, вы можете сделать это, указав, что вы хотите изменить:

(defstruct node farmer fox goose straw)
(defparameter *node* (make-node :fox 3))
(defun change-slot (object slot-name new-value)
  (setf (slot-value object slot-name) new-value))
(change-slot *node* 'fox 7)
(change-slot *node* 'goose 23)
*node*
==> #S(NODE :FARMER NIL :FOX 3 :GOOSE 23 :STRAW NIL)

Обратите внимание, что, хотя стандарт не требует slot-value для работы на structure-object, приведенный выше код работает на всех реализациях CL.

Если вы хотите, чтобы ваш код соответствовал ,Вы должны передать setter :

(defun change-slot (object setter new-value)
  (funcall setter new-value object))
(change-slot *node* #'(setf node-farmer) 6)
*node*
==> #S(NODE :FARMER 6 :FOX 3 :GOOSE 23 :STRAW NIL)

Это, увы, не гарантированно сработает либо , потому что :

этозависит от реализации, реализована ли возможность записи слота функцией setf или расширителем setf.

Таким образом, вам нужно создать свой собственный установщик:

(change-slot *node* (lambda (straw node) (setf (node-straw node) straw)) 11)
*node*
==> #S(NODE :FARMER 6 :FOX 3 :GOOSE 23 :STRAW 11)
...