আমি কীভাবে একটি ডিভভারের পুনর্নির্মাণকে বাধ্য করব?


21

ধরুন আমার কাছে একটি ইমাস লিস্প বাফার রয়েছে যা এতে রয়েছে:

(defvar foo 1)

যদি আমি কল করি eval-last-sexpবা eval-buffer, fooএটি 1 টিতে আবদ্ধ I

(defvar foo 2)

eval-last-sexpএবং eval-bufferএই লাইনটি পুনরায় কার্যকর করবেন না, fooএখনও 1 still

এটি বিশেষত চ্যালেঞ্জিং যখন এমন একাধিক বিবৃতি থাকে এবং আমাকে কোন লাইনগুলি পুনরায় মূল্যায়ন করা হয় না তা খুঁজে বের করতে হয়।

আমি কেবল ইম্যাকগুলি পুনরায় আরম্ভ করার দিকে তাকিয়েছিলাম এবং তারপরে (require 'foo), তবে তারপরে কোনও পুরানো .elc ফাইল লোড করা এড়াতে আমাকে সতর্ক থাকতে হবে।

আমি কীভাবে একেবারে, ইতিবাচকভাবে নিশ্চিত হতে পারি যে বর্তমান ফাইলে সংজ্ঞায়িত ভেরিয়েবল এবং ফাংশনগুলি নতুন ইম্যাক্সের উদাহরণে লোডিং কোডের মতো একই অবস্থায় রয়েছে?


আপনি " একেবারে, ইতিবাচকভাবে নিশ্চিত হতে পারবেন না যে ইমাকস এমন একটি অবস্থানে রয়েছে যা কোনও নতুন ইম্যাক্স ইনস্ট্যান্সে কোডটি নতুন করে লোড করার সমান " কেবল তা না করেই। আপনি যদি নিশ্চিত হতে চান যে কেবল এটির এবং অন্যান্য বৈশ্বিক ভেরিয়েবলগুলিই জাগ্রত হয় তবে আপনি makunboundবাফারে কোডটি পুনরায় মূল্যায়ন করে তাদের মানগুলি মুছে ফেলতে পারেন ।
ড্র হয়েছে

অবশ্যই, এর মতো পার্শ্ব প্রতিক্রিয়াগুলি (মূর্খ কোড) (incf emacs-major-version)আমি বারবার ঘটার সাথে বাঁচতে পারি। আমি প্রচুর defvarফর্ম সহ কোড হ্যাক করতে আগ্রহী ।
উইলফ্রেড হিউজ 21

উত্তর:


29

অন্যান্য উত্তরে বর্ণিত হিসাবে, defvarব্যবহার eval-last-sexpকরে কোনও ফর্ম মূল্যায়ন ডিফল্ট মানটিকে পুনরায় সেট করে না।

পরিবর্তে, আপনি ব্যবহার করতে পারেন eval-defun(বাধ্য C-M-xমধ্যে emacs-lisp-mode, যা আচরণ আপনার কাছে একটি বিশেষ ব্যতিক্রম হিসাবে চান প্রয়োগ ডিফল্টরূপে):

যদি বর্তমান ডিফুনটি আসলে কল হয় defvarবা defcustomএটিকে মূল্যায়ন করে এভাবে ভেরিয়েবলের ইতিমধ্যে অন্য কোনও মান রয়েছে এমনকি তার প্রাথমিক মান প্রকাশ করে ভেরিয়েবলটিকে পুনরায় সেট করে। (সাধারণত defvarএবং defcustomযদি ইতিমধ্যে একটি থাকে তবে মানটি পরিবর্তন করবেন না))


আপনার যদি বাফারের সম্পূর্ণ সামগ্রীর মূল্যায়ন করতে হয় তবে আপনি এমন একটি ফাংশন লিখতে পারেন যা শীর্ষ স্তরের ফর্মগুলি ঘুরে বেড়ায় এবং eval-defunপ্রত্যেককে কল করে। এর মতো কিছু কাজ করা উচিত:

(defun my/eval-buffer ()
  "Execute the current buffer as Lisp code.
Top-level forms are evaluated with `eval-defun' so that `defvar'
and `defcustom' forms reset their default values."
  (interactive)
  (save-excursion
    (goto-char (point-min))
    (while (not (eobp))
      (forward-sexp)
      (eval-defun nil))))

5
এই উত্তর। জাল ডিভ্যাভার বা অতিরিক্ত সেটেকের প্রয়োজন নেই। শুধু eval-defunপরিবর্তে ব্যবহার করুন eval-last-sexp । এমনকি আপনি এমন একটি ফাংশনও লিখতে পারেন eval-defunযা বাফারের প্রতিটি ফর্মকে কল করে এবং পরিবর্তে এটি ব্যবহার করতে পারে eval-buffer
মালাবারবা

1
@ মালাবারবা এই পোস্টটি প্রশ্নের উত্তর দেওয়ার চেয়ে কমই পড়েছে। eval-defunপরিবর্তে eval-last-sexp, নিশ্চিত ব্যবহার করুন , কিন্তু অসুবিধা হয় eval-buffer
গিলস 'অসন্তুষ্ট হওয়া বন্ধ করুন' 21

@ গিলস হ্যাঁ, আপনি ঠিক বলেছেন। আমি @ মালবারার eval-defunবাফারে প্রতিটি শীর্ষ-স্তরের ফর্ম কল করার ধারণার একটি অস্থায়ী বাস্তবায়ন যুক্ত করেছি ।
ffevotte

1
এই পদ্ধতির কোনওটির অভ্যন্তরে না থাকলে কাজ করবে বলে মনে defvarহয় না defun। উদাহরণ: (progn (defvar foo "bar"))
দক্ষ মোদী

2
@ কৌশালমোদি আপনি যে উত্তরোত্তর উদাহরণগুলি উল্লেখ করেছেন (নিয়মিত অভিব্যক্তিগুলি সংরক্ষণ করে ভেরিয়েবলগুলি) অনেকগুলি প্রার্থীদের মতো দেখতে defconst(যা সর্বদা পুনরায় মূল্যায়ন করা হয়)। অন্তহীন বন্ধনী
ffevotte

5

অন্যান্য উত্তরগুলির মতো বলুন, এটি ডিভভর ঠিক ঠিক কাজ করে তবে আপনি তার চারপাশে পেতে পারেন, এটি সর্বোপরি এলিস্প।

আপনি অস্থায়ীভাবে ডিফভার কীভাবে কাজ করে তা পুনরায় সংজ্ঞায়িত করতে পারেন যদি আপনি চান এবং সেই সময়ে, আপনি যে প্যাকেজগুলি পুনরায় সেট করতে চান তা পুনরায় লোড করুন।

আমি একটি ম্যাক্রো লিখেছিলাম যেখানে শরীরের মূল্যায়নের সময়, ডিফভার্স মানগুলি সর্বদা পুনরায় মূল্যায়ন করা হবে।

(defmacro my-fake-defvar (name value &rest _)
  "defvar impersonator that forces reeval."
  `(progn (setq ,name ,value)
          ',name))

(defmacro with-forced-defvar-eval (&rest body)
  "While evaluating, any defvars encountered are reevaluated"
  (declare (indent defun))
  (let ((dv-sym (make-symbol "old-defvar")))
    `(let ((,dv-sym (symbol-function 'defvar)))
       (unwind-protect
           (progn
             (fset 'defvar (symbol-function 'my-fake-defvar))
             ,@body)
         (fset 'defvar ,dv-sym)))))

ব্যবহারের উদাহরণ:

file_a.el

(defvar my-var 10)

file_b.el

(with-forced-defvar-eval
  (load-file "file_a.el")
  (assert (= my-var 10))
  (setq my-var 11)
  (assert (= my-var 11)
  (load-file "file_a.el")
  (assert (= my-var 10))

দ্রষ্টব্য: এটি কেবল ডিফারগুলি পুনর্নির্মাণের উদ্দেশ্যে ব্যবহার করা উচিত, কারণ এটি পুনর্নির্মাণ করার সময় ডকাস্ট্রিংগুলিকে উপেক্ষা করে। আপনি ডকাস্ট্রিংগুলিও প্রযোজ্য পুনরায় মূল্যায়ন সমর্থন করতে ম্যাক্রো সংশোধন করতে পারেন, তবে আমি এটি আপনার উপর ছেড়ে দেব।

আপনার ক্ষেত্রে আপনি করতে পারেন

(with-forced-defvar-eval (require 'some-package))

তবে জেনে নিন যারা এলিস্প লেখেন তারা নির্দিষ্ট হিসাবে ডিফভারের কাজ করার প্রত্যাশা করে কী করে, তারা মান নির্দিষ্ট করতে কোনও ডিআই ফাংশনে ডিফভার ব্যবহার করতে পারেন এবং সেটাক ব্যবহার করতে পারেন, তাই আপনি নির্ধারিত ভেরিয়েবলগুলি শেষ করতে পারেন তবে এটি সম্ভবত বিরল।

বিকল্প বাস্তবায়ন

এটি ব্যবহার করে আপনি কেবল বিশ্বব্যাপী ডিভ্যাওয়ারকে নতুনভাবে সংজ্ঞায়িত করতে পারেন এবং এটি প্রতীকটির মানটি INIT-VALUE আর্গে সেট করবে কিনা তা নিয়ন্ত্রণ করতে পারবেন এমনকি যদি নতুন defvar-always-reeval-valuesপ্রতীকটির মান পরিবর্তন করে চিহ্নটি সংজ্ঞায়িত করা হয় ।

;; save the original defvar definition
(fset 'original-defvar (symbol-function 'defvar))

(defvar defvar-always-reeval-values nil
  "When non-nil, defvar will reevaluate the init-val arg even if the symbol is defined.")

(defmacro my-new-defvar (name &optional init-value docstring)
  "Like defvar, but when `defvar-always-reeval-values' is non-nil, it will set the symbol's value to INIT-VALUE even if the symbol is defined."
  `(progn
     (when defvar-always-reeval-values (makunbound ',name))
     (original-defvar ,name ,init-value ,docstring)))

;; globally redefine defvar to the new form
(fset 'defvar (symbol-function 'my-new-defvar))

1
আমি নিশ্চিত আচরণের পুনরায় সংজ্ঞা দেওয়া defvarএকটি ভাল ধারণা: defvarকিছুটা আলাদা শব্দার্থবিজ্ঞানের সাথে বিভিন্ন ধরণের বিভিন্ন সম্ভাব্য ব্যবহার রয়েছে । উদাহরণস্বরূপ, আপনার ম্যাক্রোর এক হিসাবে ব্যবহার না করা হ'ল সেই (defvar SYMBOL)ফর্মটি যা বাইট-সংকলককে কোনও মান নির্ধারণ না করে ভেরিয়েবলের অস্তিত্ব সম্পর্কে বলতে ব্যবহৃত হয়।
ffevotte

আপনার যদি একেবারে defvarম্যাক্রোর সাথে নতুন সংজ্ঞা দেওয়ার দরকার হয় তবে আপনি সম্ভবত মূল defvarফর্মটির makunboundপরিবর্তে এটির পরিবর্তে প্রাকের সংজ্ঞা দেওয়া থেকে ভাল setq
ffevotte

হ্যাঁ, এটি একটি ভয়ানক ধারণা, এবং কেবলমাত্র আপনার স্ক্র্যাচ বাফারে লোড হওয়া প্যাকেজের ডিফলারগুলি পুনরায় মূল্যায়ন করার মতো জিনিসগুলির জন্য ব্যবহার করা উচিত, আপনার কখনই এ জাতীয় কিছু পাঠানো উচিত নয়।
জর্ডন বিওনদো

@ ফ্রান্সেসকোও আপনি মাকুনবাউন্ড সংস্করণ সম্পর্কে ঠিক বলেছেন, আমি এটি প্রয়োগ করেছি কিন্তু ধারণা থেকে দূরে সরে গিয়েছি, বিকল্প হিসাবে আমি আমার উত্তরটিতে এই কোডটি রেখেছি।
জর্ডন বিওনদো

3

এর defvarমূল্যায়ন করা হচ্ছে এবং আপনি যা নির্দিষ্ট করেছেন ঠিক তাই করছেন। তবে, defvarশুধুমাত্র একটি প্রাথমিক মান সেট করে:

INITVALUE alচ্ছিক আর্গুমেন্টটি মূল্যায়ন করা হয় এবং SYMBOL সেট করতে ব্যবহৃত হয়, যদি কেবল SYMBOL এর মান বাতিল হয়।

সুতরাং আপনি যা চান তা অর্জন করার জন্য আপনাকে পুনরায় মূল্যায়ন করার আগে ভেরিয়েবলটি বন্ধ করতে হবে, যেমন

(makunbound 'foo)

অথবা setqমান নির্ধারণ করতে ব্যবহার করুন , যেমন

(defvar foo nil "My foo variable.")
(setq foo 1)

এখানে যদি আপনাকে কোনও ডাস্ট্রিং নির্দিষ্ট করার প্রয়োজন না হয় আপনি defvarপুরোপুরি এড়িয়ে যেতে পারেন ।

আপনি যদি সত্যই এটি ব্যবহার করতে defvarএবং স্বয়ংক্রিয়ভাবে আবদ্ধ করতে চান তবে আপনার defvarবর্তমান বাফারে (বা অঞ্চল, বা শেষ যৌনতা ইত্যাদি) কলগুলি খুঁজে পেতে একটি ফাংশন লিখতে হবে ; makunboundপ্রত্যেকের জন্য কল ; এবং তারপরে আসল ইওল করুন।


আমি এমন একটি eval-bufferমোড়কের সাথে খেলতে যাচ্ছিলাম যা প্রথমে সমস্ত কিছু আবদ্ধ করবে, তবে @ ফ্রান্সেসকো সম্পর্কে উত্তরটি eval-defunসত্যই আপনি চান তা is
গ্লুকাস

1

নিম্নলিখিত ম্যাক্রোটিকে eval-defunতার সমর্থনকারী ফাংশনগুলিতে ট্রেস করে এবং এটিকে সংশোধন করে তৈরি করা হয়েছিল যাতে কোনও নির্দিষ্ট বাফারের অঞ্চলটি আর মূল্যায়ন করার প্রয়োজন হয় না। আমার কাছে সম্পর্কিত থ্রেডে একটি অভিব্যক্তিটিকে স্ট্রিংয়ে রূপান্তর করতে সহায়তা প্রয়োজন এবং @ টোবিয়াস উদ্ধার করতে এসেছিলেন - কীভাবে অসম্পূর্ণ ফাংশনটিকে ম্যাক্রোতে রূপান্তর করতে হবে তা শিখিয়েছিলেন। আমি মনে করি না যে আমাদের eval-sexp-add-defvarsপূর্ববর্তী হওয়া দরকার elisp--eval-defun-1, তবে কেউ যদি তা গুরুত্বপূর্ণ মনে করেন তবে দয়া করে আমাকে জানান।

;;; EXAMPLE:
;;;   (defvar-reevaluate
;;;     (defvar undo-auto--this-command-amalgamating "hello-world"
;;;     "My new doc-string."))

(defmacro defvar-reevaluate (input)
"Force reevaluation of defvar."
  (let* ((string (prin1-to-string input))
        (form (read string))
        (form (elisp--eval-defun-1 (macroexpand form))))
    form))

0

সমস্যাটি এই নয় যে লাইনটি পুনরায় মূল্যায়ন হচ্ছে না। সমস্যাটি হ'ল defvarএকটি ভেরিয়েবল এবং এর ডিফল্ট মান নির্ধারণ করে । যদি কোনও ভেরিয়েবল ইতিমধ্যে বিদ্যমান থাকে, তবে এর ডিফল্ট মান পরিবর্তন করে বর্তমান মানটি পরিবর্তন করে না। দুর্ভাগ্যক্রমে, আমি মনে করি আপনার setqপ্রতিটি পরিবর্তনশীল যার মান আপনি আপডেট করতে চান তার জন্য একটি চালানো দরকার ।

এটি ওভারকিল হতে পারে তবে আপনি যদি fooনিজের নতুন ডিফল্ট মানটিতে সহজেই আপডেট করতে সক্ষম হন তবে আপনি নিজের ফাইলটি আপডেট করতে পারেন ।

(defvar foo 2)
(setq foo 2)

তবে এর জন্য আপনার কোডে দুটি জায়গায় ডিফল্ট মান বজায় রাখা দরকার। আপনি এটি করতে পারেন:

(makunbound 'foo)
(defvar foo 2)

তবে যদি এমন কোনও সুযোগ থাকে যা fooঅন্য কোথাও ঘোষিত হয় তবে আপনার সাথে ডিল করার জন্য কিছু পার্শ্ব প্রতিক্রিয়া থাকতে পারে।


জটিল মোডে পরিবর্তনগুলি পরীক্ষা করার চেষ্টা করার সময় এটি কঠিন। আমি বরং কোডটি পরিবর্তন করব না। বিশেষভাবে eval-defunআচরণ defvarকরে, তাই পুরো বাফারগুলির জন্য অবশ্যই কিছু একই আছে?
উইলফ্রেড হিউজেস

@ উইলফ্রেড হিউজেস আপনি "পুরো বাফারদের জন্য কিছু" বলতে চাইছেন তা আমি নিশ্চিত নই। আপনি একটি একক ফাংশন চান makunboundযা বর্তমান বাফারে কোনও ভেরিয়েবল ঘোষিত হবে এবং তারপরে এটি পুনরায় মূল্যায়ন করবে? আপনি নিজের লেখা লিখতে পারেন, তবে আমি মনে করি না যে এটির জন্য বাইরের বাইরে কোনও ফাংশন রয়েছে। সম্পাদনা: কিছু মনে করবেন না, আপনি যা বলছেন তা আমি পেয়েছি। eval-defunপুরো বাফারে কাজ করে এমন একটি । দেখে মনে হচ্ছে @ জর্ডন বিয়নদোর কাছে এটির সমাধান রয়েছে।
নিস্পিও

নং সমস্যা হয় পুনর্মূল্যায়নের অভাব: defvarকিছুই না যদি পরিবর্তনশীল ইতিমধ্যে একটি মূল্য আছে (যেমন তার ডক বলেছেন: The optional argument INITVALUE is evaluated, and used to set SYMBOL, only if SYMBOL's value is void.)। সমস্যা না যে defvarডিফল্ট মান এবং বর্তমান মান পরিবর্তন। (defvar a 4) (default-value 'a) (setq a 2) (default-value 'a); তারপর যৌনতা C-x C-eপরে defvar; তারপর (default-value 'a)C-x C-e, eval-regionএবং defvarসেক্সপ এর মতো পছন্দগুলি ডিফল্ট মান পরিবর্তন করে না
ড্রিউ
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.