ট্রাম্পোলাইন কেন কাজ করে?


104

আমি কিছু কার্যকর জাভাস্ক্রিপ্ট করছি। আমি ভেবেছিলাম টেইল-কল অপটিমাইজেশন কার্যকর করা হয়েছে, তবে এটি প্রমাণিত হয়েছে যে আমি ভুল ছিল। এভাবে আমাকে ট্রাম্পলাইনিং শিখিয়েছি । এখানে এবং অন্য কোথাও কিছুটা পড়ার পরে, আমি বেসিকগুলি নামাতে সক্ষম হয়েছি এবং আমার প্রথম ট্রাম্পোলিনটি নির্মাণ করেছি:

/*not the fanciest, it's just meant to
reenforce that I know what I'm doing.*/

function loopy(x){
    if (x<10000000){ 
        return function(){
            return loopy(x+1)
        }
    }else{
        return x;
    }
};

function trampoline(foo){
    while(foo && typeof foo === 'function'){
        foo = foo();
    }
    return foo;
/*I've seen trampolines without this,
mine wouldn't return anything unless
I had it though. Just goes to show I
only half know what I'm doing.*/
};

alert(trampoline(loopy(0)));

আমার সবচেয়ে বড় সমস্যা, আমি জানি না কেন এটি কাজ করে। আমি পুনরাবৃত্ত লুপটি ব্যবহার না করে কিছুক্ষণ লুপের মধ্যে ফাংশনটি পুনরায় চালু করার ধারণা পেয়েছি। ব্যতীত, প্রযুক্তিগতভাবে আমার বেস ফাংশনটিতে ইতিমধ্যে একটি পুনরাবৃত্ত লুপ রয়েছে। আমি বেস loopyফাংশনটি চালাচ্ছি না , তবে এর ভিতরে ফাংশনটি চালাচ্ছি। foo = foo()স্ট্যাকের ওভারফ্লো হওয়ার কারণ কী থামছে ? এবং foo = foo()প্রযুক্তিগতভাবে পরিবর্তিত হচ্ছে না , বা আমি কিছু মিস করছি? সম্ভবত এটি একটি প্রয়োজনীয় মন্দ evil অথবা কিছু সিনট্যাক্স আমি অনুপস্থিত।

এটি বোঝার উপায় আছে কি? বা এটি কিছু হ্যাক যে কোনওভাবে কাজ করে? আমি অন্য সব কিছুর মধ্য দিয়ে আমার পথ তৈরি করতে সক্ষম হয়েছি, কিন্তু এই আমাকে বিস্মিত করেছে।


5
হ্যাঁ, তবে এখনও পুনরাবৃত্তি হয়। loopyউপচে পড়ে না কারণ এটি নিজেকে কল করে না
tkausl

4
"আমি ভেবেছিলাম যে টিসিও বাস্তবায়ন করা হয়েছে, তবে দেখা যাচ্ছে যে আমি ভুল ছিলাম।" এটি বেশিরভাগ পরিস্থিতিতে কমপক্ষে ভি 8-এ ছিল। আপনি উদাহরণস্বরূপ নোডের কোনও সাম্প্রতিক সংস্করণে নোডকে ভি 8 এ সক্ষম করার জন্য বলার মাধ্যমে এটি ব্যবহার করতে পারেন: ক্রোম 51 এর পর থেকে ক্রোমের এটি (একটি "পরীক্ষামূলক" পতাকার পিছনে) ছিল
টিজে ক্রোডার

125
ব্যবহারকারীর গতিবেগ শক্তি ট্রামপোলিন স্যাগস হিসাবে ইলাস্টিক সম্ভাব্য শক্তিতে রূপান্তরিত হয়, তারপরে গতিবেগের সাথে সাথে গতিবেগ শক্তিতে ফিরে আসে।
ইমিগ্রিস

66
@ মিমিবিস, এটি কোন স্ট্যাক এক্সচেঞ্জ সাইটটি যাচাই না করে এখানে যারা এসেছিল তাদের পক্ষে, আপনাকে ধন্যবাদ।
ব্যবহারকারী 1717828

4
@ jpaugh মানে কি "হপিং"? ;-)
হাল্ক

উত্তর:


89

আপনার মস্তিষ্ক ফাংশনের বিরুদ্ধে বিদ্রোহ করার কারণটি loopy()হ'ল এটি একটি বেমানান ধরণের :

function loopy(x){
    if (x<10000000){ 
        return function(){ // On this line it returns a function...
            // (This is not part of loopy(), this is the function we are returning.)
            return loopy(x+1)
        }
    }else{
        return x; // ...but on this line it returns an integer!
    }
};

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

সুতরাং আসুন লুপটি করার সময় সাবধানতার সাথে:

while(foo && typeof foo === 'function'){
    foo = foo();
}

প্রাথমিকভাবে, fooসমান loopy(0)। কী loopy(0)? ঠিক আছে, এটি 10000000 এরও কম, তাই আমরা পেয়েছি function(){return loopy(1)}। এটি সত্যবাদী মান এবং এটি একটি ফাংশন, সুতরাং লুপটি চলতে থাকবে।

এখন আমরা আসা foo = foo()foo()হিসাবে একই loopy(1)। যেহেতু 1 এখনও 10000000 এর চেয়ে কম রয়েছে, এটি প্রত্যাবর্তন করে function(){return loopy(2)}, যা আমরা তারপরে নিযুক্ত করি foo

fooএখনও একটি ফাংশন, তাই অবিরত foo সমান না হওয়া পর্যন্ত আমরা চলতে থাকি function(){return loopy(10000000)}। এটি একটি ফাংশন, তাই আমরা foo = foo()আরও একবার সময় নিই , তবে এইবার আমরা যখন কল করি তখন loopy(10000000)এক্স 10000000 এর চেয়ে কম নয় তাই আমরা কেবল এক্স ফিরে পাব। যেহেতু 10000000 এছাড়াও কোনও ফাংশন নয়, এর ফলে লুপটি শেষ হয়।


1
মন্তব্যগুলি বর্ধিত আলোচনার জন্য নয়; এই কথোপকথন চ্যাটে সরানো হয়েছে ।
ইন্নিস

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

2
@ জিমনিক জি: হ্যাঁ, এটাই আমি "অনেক বেশি টাইপিং" বলতে চাইছিলাম। সিতে আপনাকে ইউনিয়ন ঘোষণা করতে হবে, একটি কাঠামো ঘোষণা করতে হবে যা ইউনিয়নটিকে ট্যাগ করে, উভয় প্রান্তে কাঠামোটি প্যাক এবং আনপ্যাক করবে, ইউনিয়নটিকে উভয় প্রান্তে প্যাক এবং আনপ্যাক করবে এবং (সম্ভবত) কাঠামোর মধ্যে থাকা মেমরির মালিক কে? । সি ++ এর থেকে সম্ভবত কোডটি খুব কম, তবে এটি সি এর চেয়ে ধারণাগতভাবে কোনও কম জটিল নয় এবং এটি এখনও ওপির জাভাস্ক্রিপ্টের চেয়ে বেশি ভার্বোস।
কেভিন 21

অবশ্যই, আমি এটি প্রতিদ্বন্দ্বিতা করছি না, আমি কেবল মনে করি আপনি এটির উপর যে গুরুত্ব দিয়েছেন তা অদ্ভুত বা বোধগম্যতা কিছুটা শক্ত is :)
GManNickG

173

কেভিন খুব সংক্ষেপে এই নির্দিষ্ট কোড স্নিপেটটি কীভাবে কাজ করে তা নির্দেশ করে (কেন এটি যথেষ্ট বোধগম্য) পাশাপাশি আমি সাধারণ কাজে ট্রাম্পোলাইনগুলি সম্পর্কে কিছু তথ্য যুক্ত করতে চেয়েছিলাম ।

টেল-কল অপ্টিমাইজেশন (টিসিও) ছাড়াই প্রতিটি ফাংশন কল বর্তমান এক্সিকিউশন স্ট্যাকটিতে একটি স্ট্যাক ফ্রেম যুক্ত করে। ধরুন সংখ্যার একটি কাউন্টডাউন প্রিন্ট করার জন্য আমাদের একটি ফাংশন রয়েছে:

function countdown(n) {
  if (n === 0) {
    console.log("Blastoff!");
  } else {
    console.log("Launch in " + n);
    countdown(n - 1);
  }
}

আমরা যদি কল করি countdown(3), টিসিও ছাড়াই কল স্ট্যাকটি কেমন দেখায় তা বিশ্লেষণ করা যাক।

> countdown(3);
// stack: countdown(3)
Launch in 3
// stack: countdown(3), countdown(2)
Launch in 2
// stack: countdown(3), countdown(2), countdown(1)
Launch in 1
// stack: countdown(3), countdown(2), countdown(1), countdown(0)
Blastoff!
// returns, stack: countdown(3), countdown(2), countdown(1)
// returns, stack: countdown(3), countdown(2)
// returns, stack: countdown(3)
// returns, stack is empty

TCO সঙ্গে, প্রতিটি recursive কলে countdownহয় লেজ অবস্থান তাই কোনও সময় স্ট্যাক ফ্রেম বরাদ্দ করা হয় (কিছুই কলের ফলাফলের আসতে ছাড়া অন্য কিছু করার বাকি আছে)। টিসিও ছাড়া স্ট্যাকটি আরও কিছুটা বড় হয়ে যায় n

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

function trampoline(firstHop) {
  nextHop = firstHop();
  while (nextHop) {
    nextHop = nextHop()
  }
}

function countdown(n) {
  trampoline(() => countdownHop(n));
}

function countdownHop(n) {
  if (n === 0) {
    console.log("Blastoff!");
  } else {
    console.log("Launch in " + n);
    return () => countdownHop(n-1);
  }
}

এটি কীভাবে কাজ করে তার আরও ভাল ধারণা পেতে, কল স্ট্যাকটি দেখুন:

> countdown(3);
// stack: countdown(3)
// stack: countdown(3), trampoline
// stack: countdown(3), trampoline, countdownHop(3)
Launch in 3
// return next hop from countdownHop(3)
// stack: countdown(3), trampoline
// trampoline sees hop returned another hop function, calls it
// stack: countdown(3), trampoline, countdownHop(2)
Launch in 2
// stack: countdown(3), trampoline
// stack: countdown(3), trampoline, countdownHop(1)
Launch in 1
// stack: countdown(3), trampoline
// stack: countdown(3), trampoline, countdownHop(0)
Blastoff!
// stack: countdown(3), trampoline
// stack: countdown(3)
// stack is empty

প্রতিটি পদক্ষেপে countdownHopফাংশনটি পরবর্তী ঘটনার প্রত্যক্ষ নিয়ন্ত্রণ ত্যাগ করে পরিবর্তে কল করে ফাংশনটি ফিরিয়ে দেয় যা এর পরে কী হতে চায় তা বর্ণনা করে । ট্রামপোলিন ফাংশন এটি পরে এটি কল করে এবং তারপরে যে কোনও ফাংশন ফিরে আসে এবং অন্য কোনও "পরবর্তী পদক্ষেপ" না পাওয়া পর্যন্ত কল করে calls একে ট্রামোলিনিং বলা হয় কারণ ক্রিয়াকলাপটি পুনরাবৃত্ত হওয়ার পরিবর্তে প্রতিটি পুনরাবৃত্ত কল এবং ট্রামপোলিন বাস্তবায়নের মধ্যে নিয়ন্ত্রণের প্রবাহ "বাউন্স" করে। যারা নিয়ন্ত্রণ পরিত্যাগ করে তোলে recursive কল, trampoline ফাংশন নিশ্চিত করতে পারে স্ট্যাক অত্যন্ত বড় পাবেন না। পার্শ্ব নোট: trampolineসরলতার জন্য প্রত্যাবর্তন মানগুলি বাদ দেয়।

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


18

ট্রাম্পোলিন যদি ডেডিকেটেড রিটার্ন টাইপের (কোনও ফাংশনকে আপত্তি না বলার পরিবর্তে) প্রয়োগ করা হয় তবে এটি বোঝা সহজ হয়ে যায়:

class Result {}
// poor man's case classes
class Recurse extends Result {
    constructor(a) { this.arg = a; }
}
class Return extends Result {
    constructor(v) { this.value = v; }
}

function loopy(x) {
    if (x<10000000)
        return new Recurse(x+1);
    else
        return new Return(x);
}

function trampoline(fn, x) {
    while (true) {
        const res = fn(x);
        if (res instanceof Recurse)
            x = res.arg;
        else if (res instanceof Return)
            return res.value;
    }
}

alert(trampoline(loopy, 0));

এটি আপনার সংস্করণটির সাথে বৈসাদৃশ্য করুন trampolineযেখানে ফাংশন অন্য ফাংশনটি ফিরিয়ে দেয় যখন পুনরাবৃত্তি মামলা হয় এবং বেস কেস যখন এটি অন্য কিছু দেয় returns

foo = foo()স্ট্যাকের ওভারফ্লো হওয়ার কারণ কী থামছে ?

এটি নিজেকে আর বলে না। পরিবর্তে, এটি এমন একটি ফলাফল (আমার বাস্তবায়নে, আক্ষরিকভাবে ক Result) প্রদান করে যা পুনরাবৃত্তি চালিয়ে যেতে হবে কি না তা প্রকাশ করে ve

এবং foo = foo()প্রযুক্তিগতভাবে পরিবর্তিত হচ্ছে না , বা আমি কিছু মিস করছি? সম্ভবত এটি একটি প্রয়োজনীয় মন্দ evil

হ্যাঁ, এটি ঠিক লুপটির প্রয়োজনীয় দুষ্টুতা। কেউ trampolineমিউটেশন ছাড়াও লিখতে পারে তবে এর জন্য আবার পুনরাবৃত্তি প্রয়োজন:

function trampoline(fn, x) {
    const res = fn(x);
    if (res instanceof Recurse)
        return trampoline(fn, res.arg);
    else if (res instanceof Return)
        return res.value;
}

তবুও, এটি ট্রাম্পোলিন ফাংশনটি আরও ভাল কী করে তার ধারণাটি দেখায়।

ট্রাম্পলিংয়ের বিন্দুটি ফাংশন থেকে লেজ-পুনরাবৃত্ত কলকে বিমূর্ত করে তুলছে যা পুনরাবৃত্তের মান হিসাবে পুনরাবৃত্তিটি ব্যবহার করতে চায় এবং কেবলমাত্র এক জায়গায় প্রকৃত পুনরাবৃত্তি করছে - trampolineফাংশন, যা তারপরে ব্যবহারের জন্য একক জায়গায় অপ্টিমাইজ করা যায় লুপ.


foo = foo()স্থানীয় অবস্থার পরিবর্তন করার অর্থে রূপান্তরকরণ, তবে আমি সাধারণত সেই পুনঃস্থাপনটি বিবেচনা করব কারণ আপনি আসলে অন্তর্নিহিত ফাংশন অবজেক্টটি সংশোধন করছেন না, আপনি এটি ফাংশন (বা মান) দিয়ে এটি প্রতিস্থাপন করছেন।
জাব 21

@ জ্যাব হ্যাঁ, আমি যে মানটি fooধারণ করে তার পরিবর্তনের অর্থ বোঝাতে চাইনি , কেবলমাত্র পরিবর্তনশীলটি পরিবর্তিত হয়েছে। whileআপনি যদি এটির অবসান করতে চান তবে একটি লুপের জন্য কিছু পরিবর্তনীয় অবস্থা প্রয়োজন, এক্ষেত্রে পরিবর্তনশীল fooবা x
বার্গি

লেজ কল অপটিমাইজেশন, ট্রাম্পোলাইনস ইত্যাদি সম্পর্কে স্ট্যাক ওভারফ্লো প্রশ্নের জবাবে কিছুক্ষণ আগে আমি এইরকম কিছু করেছি
জোশুয়া টেলর

2
পরিব্যক্তি ছাড়া আপনার সংস্করণের recursive কল রূপান্তরিত করেছে fnকরার জন্য একটি recursive কল মধ্যে trampoline- আমি নিশ্চিত যে একটি উন্নতি হচ্ছে না।
মাইকেল অ্যান্ডারসন

1
@ মিশেল অ্যান্ডারসন এটি কেবল বিমূর্ততা প্রদর্শন করার জন্য। অবশ্যই একটি পুনরাবৃত্তি ট্রামপোলিন কার্যকর নয়।
বার্গি
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.