إنشاء مكتبة من الوظائف لتحفيز المتغيرات العالمية التعسفية

StackOverflow https://stackoverflow.com/questions/20353946

  •  25-08-2022
  •  | 
  •  

سؤال

تحديث: إذا كان لدي بعض الوظائف التي أرغب في تحديث متغير عالمي يتم تمريره كوسيطة دالة ، فيمكن للبعض أن يفعل ذلك عن طريق تمرير رمز العالم فقط (كما في حالة دفع شيء ما إلى جزء من القائمة) ، لكن الوظائف الأخرى سوف تتطلب اقتباس الرمز عند تمريره حتى أتمكن من الوصول إلى قيمة الرمز وتحول المتغير الخارجي ، المطلوب لاستخدام setQ في دالة. هذا السؤال يتعلق أساسًا بإنشاء واجهة متسقة لمستخدم هذه الوظائف دون إرباكها والتي تقوم في بعض الأحيان بتمرير الرمز ، وأوقات أخرى تمرر الرمز المقتبس

مثال على سبيل المثال لتبسيط الواجهة لمجموعة من الوظائف ، باستخدام مساعد لديه نفس الاستخدام الذي لا يهدأ عن كيفية عمل وظيفة التحور:

فيما يلي مثالان أساسيان على تقنيتي:

(defun push-something (global something)
  (push something global)
  global) ;; not necessary to return it here since the 
          ;; preceding line already does, but doing so 
          ;; for consistency with other functions and clarity

(defun push-cdr (global something)
  (push something (cdr global))
  global) ;; must return it if I am going to set the 
          ;; dynamic var to the result of this function, 
          ;; because the preceding line doesn't return the 
          ;; entire new result of the variable

;;; "dirty" function for mutating global variable using "clean" functions above:

(defun set-global (fn global &rest values)
  (setf (symbol-value global) (apply fn (copy-list (eval global)) values)))

في هذا الأخير ، يجب علي eval ال global لأنه مقتبس للاستخدام مع symbol-value ثم أنا copy-list لهذا السبب. global لا يتم تحوره مباشرة عن طريق الخطأ بأي شيء fn اخترت (كما سيكون الحال مع push-cdr والتي قد تكون غير تافهة في وظائف أكثر تعقيدًا).

انتاج:

CL-USER> (defparameter *g2* nil)
*G2*
CL-USER> (set-global #'push-something '*g2* 5)
(5)
CL-USER> *g2*
(5)
CL-USER> (set-global #'push-cdr '*g2* 99)
(5 99)
CL-USER> *g2*
(5 99)

... ويمكن استخدام نفس الوظائف مع *g1* أو *g3* إلخ. كل ذلك من خلال وظيفة الوصول set-global.

هل هذا أسلوب جيد أم سيئ ، أم أفتقد طريقة أفضل بكثير لتحقيق هذه الوظيفة؟

هل كانت مفيدة؟

المحلول 2

لماذا لا تتخلص من set-global الوظيفة تمامًا ، وإذا كنت تريد أن يكون لكل وظيفتك نفس النمط من النقل في المتغير العالمي ، فكلها تستخدمها جميعًا symbol-value لذلك لن يحتاج أي شخص يستخدم هذه الوظائف إلى معرفة أي شيء لا يتطلب اقتباسًا أمام الاسم المتغير العالمي. أليس أسهل بكثير؟

نصائح أخرى

هذا أسلوب سيء ومضيعة لوقتك.

  1. push-something يعادل cons.

  2. push-cdr هو ليس وظيفي: إنه يعدل الوسيطة في مكانها أو تفشل مع خطأ في nil جدال.

إذا كنت تريد تغيير قيمة المتغير العالمي ، فاستخدام setf صراحة أكثر وضوحا.

إذا كنت ترغب في تعديل القيمة الداخلية ذات القيمة العالمية بطريقة معقدة ، فقد تحتاج إلى كتابة وظيفة خاصة لذلك - ولكن يجب أن تكون هذه الوظيفة غير مؤلمة لحقيقة أنها تعدل القيمة المرتبطة بمتغير عالمي بدلاً من ذلك متغير معجمي.

باختصار ، هناك مشكلتان متعامدتان منفصلتان - تغيير متغير عالمي (استخدام setq) وتغيير الأجزاء الداخلية للكائن (لاأذج لطبيعته العالمية).

ملاحظة. لست متأكدًا مما تقصده بـ "SetF لا يغير قيمة المتغير العالمي عندما يكون داخل الوظيفة" ، ولكن:

(defvar *foo* 10)
*FOO* ==> 10
(defun change-foo (x) (setq *foo* x))
(change-foo 123)
*foo* ==> 123
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top