سؤال

كنت أعبث مع المجمعين في جافا سكريبت وكنت فخورا (على أمل) الحصول على عمل عندما عثرت على ويكيبيديا تقول:"يمكن التعبير عن كومبيناتور ص في حساب التفاضل والتكامل التزلج على النحو التالي:ص = س (ك (س أنا أنا)) (س (س (ك س) ك) (ك (س أنا أنا)))" ، لذلك كان علي أن أجرب ذلك:

var I = function (x) {
            return x;
        };

var K = function (x) {
        return function(){
            return x;}
        };

var S = function (x) {
           return function (y) {
               return function (z) {
                   return x(z)(y(z));
               }
           }
       };

var Y = S (K(S(I)(I))) (S(S(K(S))(K)) (K(S(I)(I))));

Y;    //evals to:
//function (z) {return x(z)(y(z));}

//And this (lifted from Crockford's Site):
var factorial = Y(function (fac) {
    return function (n) {
        return n <= 2 ? n : n * fac(n - 1);
    };
});    //fails:
//RangeError: Maximum call stack size exceeded

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

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

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

المحلول

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

أنا أعرف طريقة للتغلب على هذا (نظر أحد أساتذتي في الأمر منذ فترة) ، لكنه سيجعل التعليمات البرمجية الخاصة بك غير قابل للقراءة تماما.

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


هذا هو ما Y يبدو بعد تقييم جافا سكريبت الخاص بك التزلج التعبير:

var Y = function (q) {
    return (function(p){return q(p(p))})(function(p){return q(p(p))});
};

الآن دعونا نرى ما يحدث إذا كنت تغذية وظيفة الخاص بك function (fac) { ... }.دعنا نسمي هذه الوظيفة f:

var factorial = (function(p){return f(p(p))})(function(p){return f(p(p))});

نظرا لأنه يتم تطبيق أول وظيفة مجهولة على وسيطة ، فسيتم تقييمها في هذا:

var factorial = f(
    (function(p){return f(p(p))})(function(p){return f(p(p))})
);

في لغة مقيمة بتكاسل ، الحجة إلى f الآن أن تترك وحدها ، و f سيتم تقييم نفسها.ومع ذلك ، لأن جافا سكريبت هي لغة تقييمها بدقة (أو 'استدعاء حسب القيمة') ، فإنه يريد أن يعرف ما هي الحجة التي يحتاج إلى تمرير إلى وظيفة f قبل تشغيل هذه الوظيفة بالفعل.لذلك دعونا تقييم هذه الحجة, هلا فعلنا?

var factorial = f(f(
        (function(p){return f(p(p))})(function(p){return f(p(p))})
    )
);

أعتقد الآن أنك بدأت ترى الآن أين تسوء الأمور ، وكيف يعمل المجمع في الواقع.في أي حال ، سوف ينفد جهاز جافا سكريبت الخاص بك من مساحة المكدس ، لأنه يحاول بناء كومة لا حصر لها من المكالمات إلى f.

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