ฟังก์ชั่นเครื่องกำเนิดไฟฟ้านั้นใช้งานได้ในการเขียนโปรแกรมการทำงานหรือไม่


17

คำถามคือ:

  • เครื่องปั่นไฟทำลายกระบวนทัศน์การเขียนโปรแกรมการทำงานหรือไม่? ทำไมหรือทำไมไม่?
  • ถ้าใช่สามารถใช้เครื่องกำเนิดไฟฟ้าในการเขียนโปรแกรมเชิงหน้าที่ได้อย่างไร

พิจารณาสิ่งต่อไปนี้:

function * downCounter(maxValue) {
  yield maxValue;
  yield * downCounter(maxValue > 0 ? maxValue - 1 : 0);
}

let counter = downCounter(26);
counter.next().value; // 26
counter.next().value; // 25
// ...etc

downCounterวิธีการปรากฏไร้สัญชาติ เช่นกันการโทรdownCounterด้วยอินพุตเดียวกันก็จะส่งผลให้ออกเหมือนกัน อย่างไรก็ตามในเวลาเดียวกันการโทรnext()ไม่ได้ผลลัพธ์ที่สอดคล้องกัน

ฉันไม่แน่ใจหรือไม่ว่าเครื่องปั่นไฟทำลายกระบวนทัศน์การเขียนโปรแกรมการทำงานเพราะในตัวอย่างนี้counterเป็นวัตถุกำเนิดไฟฟ้าและอื่น ๆ โทรจะก่อให้เกิดผลเช่นเดียวกับวัตถุกำเนิดอื่นที่สร้างขึ้นด้วยเดียวกันแน่นอนnext()maxValue

เช่นกันการเรียกsomeCollection[3]ใช้อาร์เรย์จะส่งคืนองค์ประกอบที่สี่เสมอ ในทำนองเดียวกันการเรียกnext()สี่ครั้งบนวัตถุตัวสร้างจะส่งคืนองค์ประกอบที่สี่เสมอ

สำหรับบริบทเพิ่มเติมคำถามเหล่านี้เพิ่มขึ้นในขณะที่ทำงานในการเขียนโปรแกรมกะตะ บุคคลที่ตอบคำถามตั้งคำถามว่าเครื่องปั่นไฟสามารถใช้ในการเขียนโปรแกรมการทำงานหรือไม่และพวกเขายังคงอยู่ในสถานะ


2
ทุกโปรแกรมมีสถานะ คำถามจริงคือว่ามันมีคุณสมบัติเป็นสถานะการทำงานซึ่งฉันตีความว่าเป็น "รัฐไม่เปลี่ยนรูป" รัฐที่ไม่เปลี่ยนแปลงเมื่อมีการกำหนด ฉันอ้างว่าวิธีเดียวที่คุณสามารถสร้างเครื่องกำเนิดไฟฟ้าคืนสิ่งที่แตกต่างกันในการโทรแต่ละครั้งคือถ้ารัฐที่ไม่แน่นอนมีส่วนเกี่ยวข้องอย่างใด
Robert Harvey

คำตอบ:


14

ฟังก์ชั่นเครื่องกำเนิดไฟฟ้าไม่ได้พิเศษเป็นพิเศษ เราสามารถใช้กลไกที่คล้ายกันด้วยตนเองโดยเขียนฟังก์ชันตัวสร้างใหม่ในรูปแบบการติดต่อกลับ:

function downCounter(maxValue) {
  return {
    "value": maxValue,
    "next": function () {
      return downCounter(maxValue > 0 ? maxValue - 1 : 0);
     },
  };
}

let counter = downCounter(26);
counter.value; //=> 26
counter.next().value; //=> 25

เห็นได้ชัดว่า downCounterเป็นที่บริสุทธิ์และทำงานตามที่ได้รับ ไม่มีปัญหาที่นี่

โปรโตคอลเครื่องกำเนิดไฟฟ้าที่ใช้โดย JavaScript เกี่ยวข้องกับวัตถุที่ไม่แน่นอน ไม่จำเป็นต้องดูรหัสด้านบน โดยเฉพาะอย่างยิ่งวัตถุที่ไม่แน่นอนหมายความว่าเราสูญเสียความโปร่งใสในการอ้างอิง - ความสามารถในการแทนที่นิพจน์ด้วยค่าของมัน ในขณะที่ในตัวอย่างของฉันcounter.next().valueจะประเมินเสมอ25ว่าเกิดอะไรขึ้นและความถี่ที่เราทำซ้ำนี่ไม่ใช่กรณีของตัวกำเนิด JS - ณ จุดหนึ่ง26แล้ว25และมันอาจเป็นจำนวนใด ๆ นี่เป็นปัญหาถ้าเราส่งการอ้างอิงไปยังตัวสร้างไปยังฟังก์ชันอื่น:

counter.next().value; //=> 25
otherFunction(counter); // does this consume the counter?
counter.next().value; // what will this be? It depends on the otherFunction()

ชัดเจนดังนั้นเครื่องกำเนิดไฟฟ้าจึงอยู่ในสถานะจึงไม่เหมาะสมสำหรับการเขียนโปรแกรมเชิงหน้าที่ "บริสุทธิ์" โชคดีที่คุณไม่จำเป็นต้องทำการเขียนโปรแกรมฟังก์ชั่นที่บริสุทธิ์และอาจใช้งานได้จริงแทน หากเครื่องกำเนิดไฟฟ้าทำให้รหัสของคุณชัดเจนขึ้นคุณควรใช้พวกเขาโดยไม่รู้สึกผิด ท้ายที่สุดแล้ว JavaScript ไม่ได้เป็นภาษาที่ใช้งานได้จริงอย่าง Haskell

อย่างไรก็ตามใน Haskell ไม่มีความแตกต่างระหว่างการส่งคืนรายการและตัวกำเนิดเนื่องจากใช้การประเมินแบบสันหลังยาว:

downCounter :: Int -> [Int]
downCounter maxValue =
  maxValue : (downCounter (max 0 (maxValue - 1)))
-- invoke as "take n (downCounter 26)" to display n elements
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.