LINUX.ORG.RU

[cl] присваивание параметрам во внешнем окружении


0

0

Однажды поднимал этот вопрос, но так толком и не разобрался. Мой костыль:

(defun test (l)
  (setf (car l) 1))

(let ((a (list 0)))
	   (test a)
	   a)
(1)
Выглядит как-то по-костыльски. Какие есть ещё варианты? Предлагать внести объявление ф-ции во что-то типа flet и использовать внешнее при объявлении окружение(не занимаясь никакой передачей) не катит.

Опять как-то невнятно! Задача - присвоить новое значение параметру ф-ции во внешнем(для тела ф-ции) окружении. Т.е. то, что было бы идеально -

(defun test (x) 
  (setf x 1))

(let ((x 0))
  (test x) 
  x)
1 

pseudo-cat ★★★
() автор топика
Ответ на: комментарий от pseudo-cat

Если цель, конечно, не академическая, то почему бы не так:

(defun test (x)  
  (setf x 1)) 
 
(let ((x 0)) 
  (setf x (test x))
  x) 
1  

Или еще лучше:

(defun test (x)  
  (setf x 1)) 

(defmacro test-and-set(x)
  `(setf ,x (test ,x))) 

(let ((x 0)) 
  (test-and-set x)
  x) 
1  

Или так, если обобщить на любую функцию:

(defun test (x)  
  (setf x 1)) 

(defmacro func-and-set(f x)
  `(setf ,x (funcall ,f ,x))) 

(let ((x 0)) 
  (test-and-set x)
  x) 
1  

bk_ ★★
()
Ответ на: комментарий от bk_

FIXED

Или так, если обобщить на любую функцию:

(defun test (x)   
  (setf x 1))  
 
(defmacro func-and-set(f x) 
  `(setf ,x (funcall ,f ,x)))  
 
(let ((x 0))  
  (func-and-set test x) 
  x)  
1   
bk_ ★★
()

походу ты ничего не присваиваешь, а только модифицируешь составной объект. вообще, переменная с dynamic scope подойдёт.

III
()
Ответ на: FIXED от bk_

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

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

хотя в первом примере забавно получилось - использование неопределённого возвращаемого setf-ом значения для использования в качестве параметра вневшнего setf(следовательно и во внешнем окружении, к которому, по идеи, доступа вот так напрямую нет).

pseudo-cat ★★★
() автор топика
Ответ на: комментарий от III

ну в этом то и идея костыля) я понимаю как он работает, не нужно его оправдывать или ругать, просто прошу предложить другие, менее косячные, варианты.

переменная с dynamic scope подойдёт

ээ, а можно пример в коде?

pseudo-cat ★★★
() автор топика
Ответ на: комментарий от pseudo-cat

Не согласен с тем, что это костыль. Функциональщина, которая в данном случае имеет место, гласит, что функция не должна модифицировать передаваемые ей аргументы.

Поэтому, я бы сделал как в первом примере. Нечто похожее у меня уже было:

(setf some-list (remove-duplicates some-list :test #'equal))
или
(setf some-list (remove some-list 2))

bk_ ★★
()
Ответ на: комментарий от bk_

эм, я не настаиваю на функциональном подходе) Понимаешь, то что ты привёл, это конечно просто и ладно, но вопрос то совершенно о другом.

Представь, что у тебя компилится ф-ция foo в отдельном файле, используя окружение пакета pack, в котором есть ф-ция bar, в которой в let объявляется пременная var, значения которой должна интерактивно в реалтайме в бесконечном цикле изменять ф-ция foo? как ты сделаешь (setf var (foo))? )

pseudo-cat ★★★
() автор топика

> Предлагать внести объявление ф-ции во что-то типа flet и использовать внешнее при объявлении окружение(не занимаясь никакой передачей) не катит.

Имхо, ошибка в постановке задачи.

bk_ ★★
()
Ответ на: комментарий от pseudo-cat

Опять как-то невнятно! Задача - присвоить новое значение параметру ф-ции во внешнем(для тела ф-ции) окружении. Т.е. то, что было бы идеально -

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

 (defun test (x) (setf (symbol-value x) 0))

CL-USER> (let ((a 1)) (declare (special a)) (test 'a) a) 0 CL-USER> 

Либо макросами, как тут уже показали, но мне кажется что тут лучше поменять алгоритм.

cvb
()
Ответ на: комментарий от bk_

Имхо, ошибка в постановке задачи.

ну укажи мне пожалуйста эту ошибку, я не вижу

Как мне кажется такое невозможно, потому что перед вызовом функции все ее аргументы вычисляются и потом связываются с аргументами функции

собственно это и провоцирует на естественный вопрос - а как изменять связывание во внешнем окружение(ака получить «место», а не значение параметра ф-ции)?

можно костыль вроде такого городить

+вариант

что тут лучше поменять алгоритм.

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

Читать сюда до просветления:

спасибо, завтра обязательно разберусь

Организуй вменяемые структуры данных и алгоритмы.

в коде для которого это используется я работую с обычнам списком, в который с помощью push заносятся новые элементы, что тут нормализовывать? Алгоритм могу описать, если надо. Но он вроде очевиден и несложен, но лучше в примере gtk, чтобы не вводить отдельно понятие сигналов и кэлбэков.

pseudo-cat ★★★
() автор топика
Ответ на: комментарий от pseudo-cat

>собственно это и провоцирует на естественный вопрос - а как изменять связывание во внешнем окружение(ака получить «место», а не значение параметра ф-ции)?

Никак, функции так работают.

алгоритм очень удобен и краток, если его поменять - по сути провести...

Ну так может стоит пересмотреть архитектуру, вообще какая задача решается? Из описанного в топике я толком ничего не понял.

cvb
()
Ответ на: комментарий от cvb

вообще какая задача решается?

если просто, передача кэлбэку(в гтк для g-signal-connect) параметра, в который он будет записывать координаты мышки. Во время работы проги с этими координатами могут работать и другие процедуры. Глобальное хранилище не хочется делать по ряду причин.

ну что-то типа этого-

(let (coordinates function-text)
... ;в том числе и другие опрерации и кэлбыки, работающие с coordinates
; и function-text
    ;;notebook
    (let ((notebook (make-instance 'notebook :enable-popup t)))
      (box-pack-start global-vbox notebook)

      ;;text-editor
      (notebook-add-page notebook (make-text-editor function-text) (label "Coding editor"))
      
      ;;graphic editor
      (notebook-add-page notebook (make-graphic-editor coordinates) (label "Visual view"))
 ...   

вот примерчек, как что-то подобное работает в sb-thread:

(defun test ()
  (let ((out *standard-output*)
	(s (make-semaphore :name "s1")))
    (format out "~&s = ~a~%" s)
    (make-thread #'(lambda ()
		     (sleep 3)
		     (funcall (lambda (sem) 
				(signal-semaphore sem))
			      s)))
    (wait-on-semaphore s)
    (format out "~&s = ~a~%" s)))

TT> (test)
s = #S(SEMAPHORE
       :NAME s1
       :%COUNT 0
       :WAITCOUNT 0
       :MUTEX #S(MUTEX :NAME NIL :%OWNER NIL :STATE 0)
       :QUEUE #S(WAITQUEUE :NAME NIL :DATA NIL))
s = #S(SEMAPHORE
       :NAME s1
       :%COUNT 0
       :WAITCOUNT 0
       :MUTEX #S(MUTEX :NAME NIL :%OWNER NIL :STATE 0)
       :QUEUE #S(WAITQUEUE
                 :NAME NIL
                 :DATA #<THREAD FINISHED values: 1 {B78BF99}>))
NIL
TT> 

pseudo-cat ★★★
() автор топика
Ответ на: комментарий от pseudo-cat

>если просто, передача кэлбэку(в гтк для g-signal-connect) параметра, в который он будет записывать координаты мышки.

Ну видиом тогда самым простым будет хранить координаты в списке или массиве, как в первом посте, всеравно ведь их две.

cvb
()
Ответ на: комментарий от cvb

мм, список является просто обёрткой, т.е. так координаты - '((0 . 0) (1 . 1)), а так - '(((0 . 0) (1 . 1))). и работа ведётся по car-y, т.е. добавить точку не так - (push coordinates), а так - (push (car coordinates)). Мне на самом деле ваше решение больше понравилось

pseudo-cat ★★★
() автор топика
Ответ на: комментарий от pseudo-cat

Задача - присвоить новое значение параметру ф-ции во внешнем(для тела ф-ции) окружении.

где-то так

(defun test (x)
   (setf (symbol-value x) 1))
(let ((x 0))
   (test 'x)
   x)
1

antares0 ★★★★
()

Нихрена не понял.

Но если имеются координаты, и их надо менять, почему бы просто не организовать структуру и не передавать ее потом в функции?

(defstruct (point (:constructor point (x y))
                  (:conc-name pt))
  x
  y)

(defun test (point)
  (with-accessors ((x pt-x) (y pt-y))
      point
    (setf x 1 y 2)))

(let ((coords (point 0 0)))
  (test coords))
Love5an
()
Ответ на: комментарий от pseudo-cat

правильно так:

(defun test (symbol)
  (setf (symbol-value symbol) 1))

(let ((*x* 0))
  (declare (special *x*))
  (test '*x*)
  *x*)
но это для такой задачи похоже на удаление гланд через жопу.

Love5an
()
Ответ на: комментарий от Love5an

спасибо за вариант. я изменил всё в соответствии с этим.

pseudo-cat ★★★
() автор топика
Ответ на: комментарий от Love5an

знаю, ранее уже писали этот вариант. Просто интересно на чём у человека это работает без special?

кстати этот вариант не работает при попытке использования в ф-ции, переданной в gobject:g-signal-connect

pseudo-cat ★★★
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.