سؤال

انا اتابع هيكل وتفسير برامج الكمبيوتر وأثناء محاولتي حل Ex 1.3 وصلت إلى الكود التالي كمحاولة أولى لي:

(define (sumsq a b c)(
(define highest (if (> (if (> a b) a b) (if (> a c) a c)) (if (> a b) a b) (if (> a c) a c)))
(define second_h (if (> (if (> a b) b a) (if (> a c) c a)) (if (> a b) b a) (if (> a c) c a)))
(+ (* highest highest) (* second_h second_h)))

لم يكن يعمل وبحثت عن الحل ووجدته سيكب ويكي

;; ex 1.3
;; implemented using only techniques covered to this point

(define (square x) (* x x))

(define (sum-of-squares x y)
  (+ (square x) (square y)))

(define (largest-two-of-three x y z)
  (if (>= x y)
      (sum-of-squares x (if (>= y z) y z))
      (sum-of-squares y (if (>= x z) x z))))

كان الاختلاف هو أنني كنت أستخدم عبارات متعددة لتحديد المتغيرات ثم جمع المربعات، في حين أن الطريقة الصحيحة هي تحديد كل سطر كوظائف.

هل الوظائف في المخطط الأول هي الخطوط؟أم أنني فاتني الأمر برمته؟

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

المحلول

ما كتبته (مطروحًا منه قوسًا إضافيًا) هو:

(define (sumsq a b c)
  (define highest
    (if (> (if (> a b) a b)
           (if (> a c) a c))
      (if (> a b) a b)
      (if (> a c) a c)))
  (define second_h
    (if (> (if (> a b) b a)
           (if (> a c) c a))
      (if (> a b) b a)
      (if (> a c) c a)))
  (+ (* highest highest) (* second_h second_h)))

يقوم حلهم بفصل المربعات ومجموع المربعات إلى وظائف منفصلة، ​​لكنني لا أعتقد أن هذا هو المهم.لا يكتب (+ (* a a) (* b b)) سوف يمنعك من تسمية القيمتين اللتين تقوم بحسابهما، مما سيسمح لك بكتابة الدالة كتعبير واحد كبير في النهاية، ولكن هناك أشياء أكبر يجب أن تقلق بشأنها الآن.

أعتقد أن المشكلة التي تواجهها هي أن تعبيراتك (إذا...) كبيرة جدًا بحيث لا يمكن فهمها بسهولة.لاحظ أن هناك نمطين يظهران عدة مرات: (if (> a b) a b) و (if (> a b) b a).هذه هي الدالات القصوى والدقيقة، لذا من المفيد تعريفها على هذا النحو:

(define (min a b) (if (< a b) a b))
(define (max a b) (if (< a b) b a))

بهذه الطريقة، يمكنك إعادة كتابة الحل الخاص بك على النحو التالي:

(define (sumsq a b c)
  (define highest
    (if (> (max a b) (max a c))
      (max a b)
      (max a c)))
  (define second_h
    (if (> (min a b) (min a c))
      (min a b)
      (min a c)))
  (+ (* highest highest) (* second_h second_h)))

تبسيطها مرة أخرى يعطي:

(define (sumsq a b c)
  (define highest
    (max (max a b) (max a c)))
  (define second_h
    (max (min a b) (min a c)))
  (+ (* highest highest) (* second_h second_h)))

لاحظ كيف أن هذه الكتابة أسهل بكثير في التفكير فيها، (max (max a b) (max a c)) ومن الواضح أن الحد الأقصى ل a b و c, ، ويمكن في الواقع إعادة كتابتها كـ (max (max a b) c).انظر الى second_h, ومع ذلك، ليس من الواضح أن هذا صحيح.ماذا سيحدث متى a هو أصغر القيم الثلاث؟

الحيلة التي يستخدمونها في حلهم هي المقارنة أولاً x و y.لو x < y, ، فأنت تعلم ذلك y ليس الأصغر بين الثلاثة، فهو إما الأعلى أو الثاني الأعلى.الرقم الآخر الذي تريد استخدامه هو الأعلى x و z, ، نظرًا لأن الجزء السفلي من هذين سيكون الأصغر بين الثلاثة، وهو ما تريد تجاهله.ينطبق منطق مماثل عندما y < x.

نصائح أخرى

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

(define (sumsq a b c)
  ((define highest 
     (if (> (if (> a b) a b)
            (if (> a c) a c))
         (if (> a b) a b)
         (if (> a c) a c)))
   (define second-h
     (if (> (if (> a b) b a)
            (if (> a c) c a))
         (if (> a b) b a)
         (if (> a c) c a)))
   (+ (* highest highest)
      (* second-h second-h)))

أول شيء يجب ملاحظته:الأقواس غير متطابقة؛هناك واحدة مفتوحة أكثر من مغلقة.يُظهر الفحص الدقيق أن أحد القوسين الافتتاحيين في السطر الثاني خاطئ.هذا، بالمناسبة، هو الذي كان متدليًا بطريقة ما في نهاية سطرك الأول.وأخاطر بتخمين أنه عندما حاولت تقييم ذلك، لم يحدث شيء، حيث انتظر القارئ نهاية البيان.

المسافة البادئة الصحيحة مهمة جدًا.أعتقد أن SICP لا يشرح ذلك بشكل واضح، على الرغم من أن الأمثلة تتم بهذه الطريقة بشكل عام.لقد وجدت دليل الأسلوب هنا.

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

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

واحدة من أفكار المخطط هي bottom-up programming حيث تقوم بإنشاء وظيفة لكل عملية مفاهيمية.هذا هو النهج الموصى به في العديد من لغات البرمجة الوظيفية.

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

الحل الخاص بك كان هذا النموذج:(تعريف (وظيفة بارام) (تعريف...) (تعريف...))

لكن التعريف يحتاج إلى هذا النموذج:(تعريف (func Param)) الجسم)

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

للإجابة على السؤال "هل وظائف المخطط الواحدة؟" تحتاج إلى التحقيق في نموذج "البداية" ، والذي يبدو هكذا:(البداية (+ 1 1) (+ 2 2)) => 4

في المثال أعلاه، تم طرح نتيجة (+ 1 1) جانبًا، لذلك يمكنك أن ترى أن البداية تكون منطقية فقط عندما يكون للأشياء الموجودة بداخلها آثار جانبية.

يجب أن تدرك أن بعض أجزاء Scheme (خاصة Let و lambda) لها بداية ضمنية حول الجسم.إذن هذا صحيح:

  (let ((x 1))
    (+ 1 1)
    (+ 2 2))

حتى بدون بداية.وهذا يجعل كتابة الكود أسهل.

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

يطلب منك التمرين 1.3 تحديد إجراء يستخدم ثلاثة أرقام كوسيطات ويعيد مجموع مربعي الرقمين الأكبرين.من السهل تحديد إجراء كهذا باستخدام إجراءات المخطط المضمنة square, max, ، و min, ، ولكننا لم نواجه هذه الإجراءات في تلك المرحلة من الكتاب بعد، لذا سأقوم بتعريفها أيضًا.

(define (square x)
   (* x x))

(define (max x y)
   (if (> x y) x y))

(define (min x y)
   (if (< x y) x y))

(define (sum-of-highest-squares x y z)
   (+ (square (max x y))
      (square (max (min x y) z))))

ال sum-of-highest-squares يعمل الإجراء عن طريق إضافة مربع الحد الأقصى لـ x وy (يتم حذف الحد الأقصى لهذين الاثنين من كونه الأدنى بين الثلاثة) ومربع الحد الأقصى للرقمين المتبقيين (الحد الأدنى لـ x وy، والذي سيكون أيًا كانت القيمة المتبقية من الخطوة الأولى)، وz.

ملحوظة:هذا من منشور مدونتي تمارين SICP 1.1 - 1.5.توجد روابط ستنقلك إلى الكثير من حلول SICP الأخرى الموجودة هناك أيضًا.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top