سؤال

نعم. لقد كنت العبقات مع عباءة وأريد باستمرار في نفس المشكلة. دعونا نأخذ هذه الشظية الصغيرة من التعليمات البرمجية:

(let [x 128]
  (while (> x 1)
    (do
      (println x)
      (def x (/ x 2)))))

الآن أتوقع هذا لطباعة تسلسل بدءا من 128 كما هو:

128
64
32
16
8
4
2

بدلا من ذلك، إنها حلقة لا حصر لها، طباعة 128 مرارا وتكرارا. من الواضح أن التأثير الجانبي المقصود لا يعمل.

فكيف من المفترض أن أعيد تعريف قيمة X في حلقة مثل هذا؟ أدرك أن هذا قد لا يكون lisp مثل (يمكنني استخدام وظيفة مجهولة يرفض ذلك، ربما)، ولكن إذا لم أكتشف كيفية ضبط المتغير مثل هذا، فسوف أذهب إلى الجنون.

سيكون تخمين الآخر هو استخدام مجموعة!، ولكن هذا يعطي "هدف مهمة غير صالح"، لأنني لست في نموذج ملزم.

من فضلك، تنوير لي كيف من المفترض أن يعمل هذا.

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

المحلول

def يحدد Toplevel Var، حتى إذا كنت تستخدمه في وظيفة أو حلقة داخلية من بعض التعليمات البرمجية. ما تحصل عليه let ليست فارس. لكل الوثائق ل let:

السكان المحليون الذين تم إنشاؤهم مع المال ليسوا متغيرات. بمجرد إنشاء قيمهم لا تتغير أبدا!

(التركيز على الألغام.) لا تحتاج إلى حالة قابلة للتغيير على مثالك هنا؛ يمكنك استخدام loop و recur.

(loop [x 128]
  (when (> x 1)
    (println x)
    (recur (/ x 2))))

إذا كنت تريد أن تكون يتوهم، فيمكنك تجنب الصريح loop تماما.

(let [xs (take-while #(> % 1) (iterate #(/ % 2) 128))]
  (doseq [x xs] (println x)))

اذا أنت حقا أراد استخدام حالة قابلة للتغيير، ذرة قد تعمل.

(let [x (atom 128)]
  (while (> @x 1)
    (println @x)
    (swap! x #(/ %1 2))))

(لا تحتاج do; while يلف جسده في واحدة صريحة بالنسبة لك.) إذا كنت حقا حقا يريد أن يفعل هذا مع فارس يجب عليك القيام بشيء فظيع مثل هذا.

(with-local-vars [x 128]
  (while (> (var-get x) 1)
    (println (var-get x))
    (var-set x (/ (var-get x) 2))))

ولكن هذا قبيح للغاية وليس عباءة اصطلاحية على الإطلاق. لاستخدام Clojure بشكل فعال، يجب أن تحاول التوقف عن التفكير من حيث الحالة القابلة للتغيير. بالتأكيد سيقودك مجنونا في محاولة كتابة رمز عباءة في نمط غير وظيفي. بعد فترة من الوقت قد تجد أنه مفاجأة سارة كيف نادرا ما تحتاج فعليا إلى متغيرات قابلة للتغيير.

نصائح أخرى

Vars (هذا ما تحصل عليه عندما تقوم "Def" بشيء) لا يعني إعادة تعيينه (ولكن يمكن أن يكون):

user=> (def k 1)
#'user/k
user=> k
1

لا يوجد شيء يمنعك من القيام به:

user=> (def k 2)
#'user/k
user=> k
2

إذا كنت ترغب في إنشاء موضوع "مكان" محلي "، يمكنك استخدام" ملزم "و" تعيين! ":

user=> (def j) ; this var is still unbound (no value)
#'user/j
user=> j
java.lang.IllegalStateException: Var user/j is unbound. (NO_SOURCE_FILE:0)
user=> (binding [j 0] j)
0

لذلك، يمكنك كتابة حلقة مثل هذا:

user=> (binding [j 0]
         (while (< j 10)
           (println j)
           (set! j (inc j))))
0
1
2
3
4
5
6
7
8
9
nil

لكنني أعتقد أن هذا غير طبيعي.

إذا كنت تعتقد أن وجود متغيرات محلية متغيرة في الوظائف النقية ستكون ميزة مريحة لطيفة لا تؤذي، لأن الوظيفة لا تزال لا تزال نقية، فقد تكون مهتما بمناقشة القائمة البريدية هذه حيث يشرح Hichkey Hickey أسبابه لإزالةها من اللغة وبعد لماذا لا تقليل السكان المحليين؟

الجزء ذو الصلة:

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

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

غالبية الوظائف اللاحقة تتعلق بتنفيذ with-local-vars دقيق ؛)

يمكنك استخدام أكثر اعتمادا iterate و take-while في حين أن،

user> (->> 128
           (iterate #(/ % 2))
           (take-while (partial < 1)))

(128 64 32 16 8 4 2)
user>
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top