พิสูจน์ได้ว่าคอมไพเลอร์ไม่สามารถตรวจพบโค้ดที่ตายแล้ว


32

ฉันวางแผนที่จะสอนหลักสูตรฤดูหนาวในหัวข้อที่หลากหลายซึ่งหนึ่งในนั้นจะเป็นคอมไพเลอร์ ตอนนี้ฉันเจอปัญหานี้ขณะที่คิดถึงงานมอบหมายที่จะมอบให้ตลอดทั้งไตรมาส แต่มันทำให้ฉันนิ่งงันดังนั้นฉันจึงอาจใช้มันเป็นตัวอย่างแทน

public class DeadCode {
  public static void main(String[] args) {
     return;
     System.out.println("This line won't print.");
  }
}

returnในโปรแกรมข้างต้นจะเห็นได้ชัดว่าคำสั่งพิมพ์จะไม่ดำเนินการเพราะ คอมไพเลอร์บางครั้งให้คำเตือนหรือข้อผิดพลาดเกี่ยวกับรหัสที่ตายแล้ว ตัวอย่างเช่นรหัสข้างต้นจะไม่รวบรวมใน Java อย่างไรก็ตามคอมไพเลอร์ javac จะไม่ตรวจจับอินสแตนซ์ทั้งหมดของรหัสที่ตายแล้วในทุกโปรแกรม ฉันจะพิสูจน์ได้อย่างไรว่าคอมไพเลอร์ไม่สามารถทำได้?


29
พื้นหลังของคุณคืออะไรและบริบทที่คุณจะสอนคืออะไร? จะทื่อฉันกังวลเล็กน้อยว่าคุณต้องถามสิ่งนี้เพราะคุณจะต้องสอน แต่โทรดีถามที่นี่!
Raphael


9
@ MichaelKjörlingการตรวจจับโค้ด Dead เป็นไปไม่ได้แม้ว่าจะไม่มีข้อควรพิจารณาก็ตาม
David Richerby

2
BigInteger i = 0; while(isCollatzConjectureTrueFor(i)) i++; printf("Hello world\n");
user253751

2
@immibis คำถามที่ถามหาหลักฐานว่าการตรวจสอบรหัสที่ตายแล้วเป็นไปไม่ได้ คุณได้ยกตัวอย่างว่าการตรวจจับโค้ดที่ถูกต้องนั้นจำเป็นต้องมีการแก้ปัญหาแบบเปิดในวิชาคณิตศาสตร์ แต่นั่นไม่ได้พิสูจน์ให้เห็นว่าการตรวจสอบรหัสที่ตายแล้วเป็นไปไม่ได้
David Richerby

คำตอบ:


57

ทุกอย่างมาจากความลังเลของปัญหาการหยุดชะงัก สมมติว่าเรามีฟังก์ชั่นรหัสตายตัว "สมบูรณ์แบบ" บางเครื่องทัวริง M และอินพุตสตริง x และโพรซีเดอร์ที่มีลักษณะดังนี้:

Run M on input x;
print "Finished running input";

ถ้า M ทำงานอย่างถาวรเราจะลบคำสั่ง print เนื่องจากเราจะไม่ไปถึงมัน หาก M ไม่ทำงานตลอดไปเราต้องเก็บคำสั่ง print ไว้ ดังนั้นหากเรามีตัวกำจัดรหัสตายแล้วมันยังช่วยให้เราแก้ปัญหาการหยุดชะงักดังนั้นเราจึงรู้ว่าไม่มีตัวกำจัดรหัสตายดังกล่าว

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

โดยปกติจะทำโดยการสร้าง "control-flow graph" เราทำการตั้งสมมติฐานอย่างง่ายเช่น "จุดสิ้นสุดของขณะที่ลูปเชื่อมต่อกับจุดเริ่มต้นและคำสั่งหลังจากนั้น" แม้ว่ามันจะทำงานตลอดไปหรือทำงานเพียงครั้งเดียว ในทำนองเดียวกันเราสมมติว่าคำสั่ง if สามารถเข้าถึงสาขาทั้งหมดแม้ว่าในความเป็นจริงแล้วบางคนไม่เคยใช้ การทำให้เข้าใจง่ายประเภทนี้ช่วยให้เราสามารถลบ "รหัสที่ตายแล้วอย่างเห็นได้ชัด" เช่นเดียวกับตัวอย่างที่คุณให้ในขณะที่ยังเหลือ decidable

หากต้องการชี้แจงความสับสนเล็กน้อยจากความคิดเห็น:

  1. Nitpick: สำหรับ M ที่ตายตัวนี่จะสามารถตัดสินใจได้เสมอ M ต้องเป็นอินพุต

    ดังที่ราฟาเอลบอกในตัวอย่างของฉันเราถือว่าทัวริงจักรเป็นข้อมูลป้อนเข้า แนวคิดคือถ้าเรามีอัลกอริทึม DCE ที่สมบูรณ์แบบเราจะสามารถสร้างข้อมูลโค้ดที่ฉันให้กับเครื่องทัวริงใด ๆและการมี DCE จะช่วยแก้ปัญหาการหยุดชะงัก

  2. ไม่เชื่อ กลับเป็นคำสั่งทื่อในการดำเนินการส่งต่อตรงไม่มีสาขาไม่ยากที่จะตัดสินใจ (และคอมไพเลอร์ของฉันบอกฉันว่ามันสามารถหาสิ่งนี้ได้)

    สำหรับปัญหาที่เพิ่มขึ้น njzk2: คุณถูกต้องอย่างแน่นอนในกรณีนี้คุณสามารถระบุได้ว่าไม่มีทางที่คำสั่งหลังจากที่สามารถเข้าถึงการส่งคืนได้ นี่เป็นเพราะมันง่ายพอที่เราจะสามารถอธิบายการควบคุมการไหลได้โดยใช้ข้อ จำกัด กราฟการไหล (เช่นไม่มีขอบออกจากคำสั่ง return) แต่ไม่มีตัวกำจัดรหัสที่สมบูรณ์แบบซึ่งจะกำจัดรหัสที่ไม่ได้ใช้ทั้งหมด

  3. ฉันไม่ใช้การพิสูจน์ที่ขึ้นอยู่กับอินพุตสำหรับการพิสูจน์ หากมีการป้อนข้อมูลของผู้ใช้เช่นนั้นที่สามารถอนุญาตให้โค้ดมี จำกัด มันถูกต้องสำหรับคอมไพเลอร์ที่จะคิดว่าสาขาต่อไปนี้จะไม่ตาย ฉันไม่เห็นสิ่งที่ upvotes เหล่านี้มีให้เห็นได้ชัด (เช่น stdin ไม่รู้จบ) และผิด

    สำหรับTomášZato: มันไม่ใช่ข้อพิสูจน์ที่ขึ้นอยู่กับอินพุต ค่อนข้างตีความว่ามันเป็น "forall" มันทำงานได้ดังต่อไปนี้: สมมติว่าเรามีอัลกอริธึม DCE ที่สมบูรณ์แบบ หากคุณให้ทัวริงเครื่อง M และอินพุต x ให้ฉันฉันสามารถใช้อัลกอริทึม DCE ของฉันเพื่อตรวจสอบว่า M หยุดการทำงานหรือไม่โดยการสร้างโค้ดขนาดเล็กด้านบนและดูว่าคำสั่งการพิมพ์ถูกลบหรือไม่ เทคนิคนี้การทิ้งพารามิเตอร์โดยพลการเพื่อพิสูจน์คำสั่งทั้งหมดเป็นเรื่องปกติในวิชาคณิตศาสตร์และตรรกะ

    ฉันไม่เข้าใจประเด็นของTomášZatoอย่างเต็มที่เกี่ยวกับการ จำกัด รหัส แน่นอนว่ารหัสนั้นมี จำกัด แต่อัลกอริธึม DCE ที่สมบูรณ์แบบจะต้องใช้กับรหัสทั้งหมดซึ่งเป็นชุด infinte เช่นเดียวกันในขณะที่โค้ดตัวเองมี จำกัด ชุดป้อนข้อมูลที่เป็นไปได้จะมี จำกัด เช่นเดียวกับเวลาทำงานของรหัส

    สำหรับการพิจารณาสาขาสุดท้ายที่ยังไม่ตาย: มันปลอดภัยในแง่ของ "การประมาณแบบอนุรักษ์นิยม" ที่ฉันพูดถึง แต่มันก็ไม่เพียงพอที่จะตรวจจับอินสแตนซ์ของรหัสตายทั้งหมดตามที่ OP ขอ

พิจารณารหัสเช่นนี้:

while (true)
  print "Hello"
print "goodbye"

เห็นได้ชัดว่าเราสามารถลบได้print "goodbye"โดยไม่ต้องเปลี่ยนพฤติกรรมของโปรแกรม ดังนั้นจึงเป็นรหัสตาย แต่ถ้ามีการเรียกใช้ฟังก์ชั่นที่แตกต่างกันแทนที่จะ(true)อยู่ในwhileเงื่อนไขเราก็ไม่รู้ว่าเราสามารถลบมันออกได้หรือไม่

โปรดทราบว่าฉันไม่ได้มากับสิ่งนี้ด้วยตัวเอง มันเป็นผลลัพธ์ที่รู้จักกันดีในทฤษฎีของคอมไพเลอร์ มันเป็นที่กล่าวถึงในเสือหนังสือ (คุณอาจจะสามารถที่จะดูว่าพวกเขาพูดคุยเกี่ยวกับในในหนังสือของ Google


1
@ njzk2: เรากำลังพยายามแสดงว่าเป็นไปไม่ได้ที่จะสร้างตัวกำจัดรหัสตายที่กำจัดรหัสตายทั้งหมดไม่ใช่ว่าเป็นไปไม่ได้ที่จะสร้างตัวกำจัดรหัสตายที่กำจัดรหัสตายบางตัว ตัวอย่างการพิมพ์หลังจากส่งคืนสามารถกำจัดได้อย่างง่ายดายโดยใช้เทคนิคกราฟการไหลของการควบคุม แต่ไม่สามารถกำจัดรหัสที่ตายทั้งหมดได้ด้วยวิธีนี้
user2357112 รองรับ Monica

4
คำตอบนี้อ้างอิงความคิดเห็น ขณะที่ฉันอ่านคำตอบฉันต้องข้ามไปที่ความคิดเห็นแล้วกลับไปที่คำตอบ สิ่งนี้ทำให้เกิดความสับสน (เป็นสองเท่าดังนั้นเมื่อคุณพิจารณาว่าความคิดเห็นนั้นบอบบางและอาจสูญหายได้) คำตอบในตัวเองจะอ่านง่ายกว่ามาก
TRiG

1
nn

3
MxMx

1
jmite โปรดรวมความคิดเห็นที่ถูกต้องลงในคำตอบเพื่อให้คำตอบนั้นเป็นของตัวเอง จากนั้นตั้งค่าสถานะความคิดเห็นทั้งหมดที่ล้าสมัยดังนั้นเราจึงสามารถล้างข้อมูลได้ ขอบคุณ!
Raphael

14

นี่เป็นคำตอบที่บิดไปมาของ jmite ที่หลีกเลี่ยงความสับสนที่อาจเกิดขึ้นเกี่ยวกับการไม่เลิกจ้าง ฉันจะให้โปรแกรมที่หยุดตัวเองอยู่เสมออาจมีรหัสตายตัว แต่เราไม่สามารถตัดสินใจได้ว่าจะมีอัลกอริทึม (เสมอ) หรือไม่

พิจารณาคลาสอินพุตต่อไปนี้สำหรับตัวระบุ Dead-Code:

simulateMx(n) {
  simulate TM M on input x for n steps
  if M did halt
    return 0
  else
    return 1
}

ตั้งแต่Mและxได้รับการแก้ไขsimulateMsมีรหัสตายด้วยreturn 0และถ้าหากไม่หยุดบนMx

MxMM

ดังนั้นการตรวจสอบ Dead-Code จึงไม่สามารถคำนวณได้

ในกรณีที่คุณไม่คุ้นเคยกับการลดลงเป็นเทคนิคหลักฐานในบริบทนี้ผมขอแนะนำให้วัสดุอ้างอิงของเรา


5

วิธีง่ายๆในการแสดงคุณสมบัติประเภทนี้โดยไม่ต้องจมอยู่ในรายละเอียดคือการใช้บทแทรกต่อไปนี้:

บทแทรก:สำหรับคอมไพเลอร์ใด ๆ C สำหรับภาษาทัวริงสมบูรณ์มีฟังก์ชันundecidable_but_true()ที่ไม่มีการขัดแย้งและส่งกลับค่าบูลีนจริงเช่นนั้น C ไม่สามารถทำนายได้ว่าundecidable_but_true()ผลตอบแทนจริงหรือเท็จ

โปรดทราบว่าฟังก์ชั่นขึ้นอยู่กับคอมไพเลอร์ รับฟังก์ชั่นundecidable_but_true1()คอมไพเลอร์สามารถเพิ่มด้วยความรู้ว่าฟังก์ชั่นนี้จะส่งกลับจริงหรือเท็จ; แต่มีฟังก์ชั่นอื่น ๆundecidable_but_true2()ที่จะไม่ครอบคลุมอยู่เสมอ

การพิสูจน์:ตามทฤษฎีบทของไรซ์คุณสมบัติ“ ฟังก์ชันนี้คืนค่าจริง” ไม่สามารถพิสูจน์ได้ ดังนั้นอัลกอริทึมการวิเคราะห์แบบสแตติกใด ๆ จึงไม่สามารถตัดสินใจคุณสมบัตินี้สำหรับฟังก์ชั่นที่เป็นไปได้ทั้งหมด

ผลที่ได้รับ:เมื่อคอมไพเลอร์ C โปรแกรมต่อไปนี้มีรหัสที่ไม่สามารถตรวจพบได้:

if (!undecidable_but_true()) {
    do_stuff();
}

หมายเหตุเกี่ยวกับ Java: คำสั่งภาษาจาวาที่คอมไพเลอร์ปฏิเสธโปรแกรมบางอย่างที่มีโค้ดที่ไม่สามารถเข้าถึงได้ในขณะที่การบังคับให้รหัสนั้นมีเหตุผลที่จุดที่เข้าถึงได้ทั้งหมด (เช่นโฟลว์ควบคุมในฟังก์ชันที่ไม่ใช่โมฆะจะต้องจบด้วยreturnคำสั่ง) ภาษาระบุวิธีการวิเคราะห์รหัสที่ไม่สามารถเข้าถึงได้อย่างชัดเจน หากไม่เป็นเช่นนั้นจะเป็นไปไม่ได้ที่จะเขียนโปรแกรมพกพา รับโปรแกรมของแบบฟอร์ม

some_method () {
    <code whose continuation is unreachable>
    // is throw InternalError() needed here?
}

มีความจำเป็นต้องระบุว่าในกรณีใดรหัสที่ไม่สามารถเข้าถึงได้จะต้องตามด้วยรหัสอื่นและในกรณีใดจะต้องไม่ตามด้วยรหัสใด ๆ ตัวอย่างของโปรแกรม Java ที่มีรหัสที่ไม่สามารถเข้าถึงได้ แต่ไม่ใช่ในลักษณะที่ Java compilers ได้รับอนุญาตให้สังเกตเห็นเกิดขึ้นใน Java 101:

String day_of_week(int n) {
    switch (n % 7) {
    case 0: return "Sunday";
    case 1: case -6: return "Monday";
    …
    case 6: case -1: return "Saturday";
    }
    // return or throw is required here, even though this point is unreachable
}

โปรดทราบว่าคอมไพเลอร์บางตัวสำหรับบางภาษาอาจสามารถตรวจพบว่าจุดสิ้นสุดday_of_weekไม่สามารถเข้าถึงได้
user253751

@immibis ใช่ตัวอย่างเช่นนักเรียน CS101 สามารถทำได้ในประสบการณ์ของฉัน (แม้ว่านักเรียน CS101 ที่เป็นที่ยอมรับไม่ใช่เครื่องมือวิเคราะห์เสียงคงที่ แต่พวกเขามักลืมเกี่ยวกับกรณีลบ) นั่นเป็นส่วนหนึ่งของจุดของฉัน: มันเป็นตัวอย่างของโปรแกรมที่มีโค้ดที่ไม่สามารถเข้าถึงได้ซึ่งคอมไพเลอร์ Java จะไม่ตรวจจับ (อย่างน้อยก็อาจเตือนเกี่ยวกับ แต่ไม่อาจปฏิเสธได้)
Gilles 'หยุดความชั่วร้าย'

1
ฉันกลัวว่าถ้อยคำของเลมม่าจะทำให้เข้าใจผิดได้ดีที่สุดโดยมีความผิดเล็กน้อย ความไม่สามารถตัดสินใจได้นั้นเหมาะสมถ้าคุณพูดถึงชุดของอินสแตนซ์ (ไม่มีที่สิ้นสุด) ของอินสแตนซ์ (คอมไพเลอร์จะผลิตคำตอบสำหรับทุกฟังก์ชั่นและเรารู้ว่ามันไม่สามารถเป็นที่ถูกต้องเสมอไป แต่บอกว่ามีอินสแตนซ์ undecidable เดียวปิด.) วรรคของคุณระหว่างแทรกและหลักฐาน (ซึ่งไม่ค่อยตรงกับบทแทรก ตามที่ระบุไว้) พยายามแก้ไขสิ่งนี้ แต่ฉันคิดว่ามันจะเป็นการดีกว่าที่จะกำหนดบทแทรกที่ถูกต้องชัดเจน
Raphael

@ ราฟาเอลเอ่อ? ไม่คอมไพเลอร์ไม่ต้องการคำตอบสำหรับคำถาม“ ฟังก์ชั่นนี้คงที่หรือไม่” ไม่จำเป็นต้องแยกความแตกต่าง“ ฉันไม่รู้” จาก“ ไม่” เพื่อสร้างรหัสการทำงาน แต่ไม่เกี่ยวข้องที่นี่เนื่องจากเราสนใจเฉพาะส่วนการวิเคราะห์แบบคงที่ของคอมไพเลอร์ไม่ใช่ในส่วนการแปลรหัส ฉันไม่เข้าใจสิ่งที่คุณพบว่าทำให้เข้าใจผิดหรือไม่ถูกต้องเกี่ยวกับคำสั่งของบทแทรก - เว้นแต่ประเด็นของคุณคือฉันควรเขียน "ตัววิเคราะห์แบบคงที่" แทน "คอมไพเลอร์"?
Gilles 'หยุดความชั่วร้าย'

คำสั่งดูเหมือน "undecidability หมายความว่ามีอินสแตนซ์ที่ไม่สามารถแก้ไขได้" ซึ่งเป็นสิ่งที่ผิด (ฉันรู้ว่าคุณไม่ได้ตั้งใจจะพูดอย่างนั้น แต่นั่นเป็นวิธีที่สามารถอ่านถึงความไม่ระมัดระวัง / มือใหม่, imho.)
Raphael

3

คำตอบของ jmite ใช้กับโปรแกรมที่จะออกจากการคำนวณหรือไม่ - เพราะมันไม่มีที่สิ้นสุดฉันจะไม่เรียกรหัสหลังจากที่มันตาย

อย่างไรก็ตามมีวิธีอื่น: ปัญหาที่มีคำตอบ แต่ไม่ทราบ:

public void Demo()
{
  if (Chess.Evaluate(new Chessboard(), int.MaxValue) != 0)
    MessageBox.Show("Chess is unfair!");
  else
    MessageBox.Show("Chess is fair!");
}

public class chess
{
  public Int64 Evaluate(Chessboard Board, int SearchDepth)
  {
  ...
  }
}

รูทีนนี้โดยไม่มีข้อสงสัยจะมีรหัสตาย - ฟังก์ชั่นจะกลับคำตอบที่ดำเนินการหนึ่งเส้นทาง แต่ไม่ได้อื่น โชคดีที่พบมัน! ความทรงจำของฉันไม่ใช่คอมพิวเตอร์เชิงทฤษฎีที่สามารถแก้ปัญหานี้ได้ในช่วงอายุของจักรวาล

รายละเอียดเพิ่มเติม:

Evaluate()คำนวณฟังก์ชั่นที่ด้านข้างชนะเกมหมากรุกถ้าทั้งสองฝ่ายเล่นได้อย่างสมบูรณ์แบบ (มีความลึกการค้นหาสูงสุด)

ผู้ประเมินผลหมากรุกมักจะมองไปข้างหน้าในทุก ๆ ความเคลื่อนไหวที่เป็นไปได้บางระดับความลึกที่กำหนดและจากนั้นพยายามให้คะแนนกระดาน ณ จุดนั้น (บางครั้งการขยายสาขาบางอย่างไกลออกไป คือ 17695 ครึ่งหนึ่งของการค้นหาที่ละเอียดถี่ถ้วนมันจะข้ามทุกเกมหมากรุกที่เป็นไปได้ เนื่องจากทุกเกมจบไม่มีปัญหาในการพยายามตัดสินใจว่าตำแหน่งแต่ละบอร์ดนั้นดีเพียงใด (และไม่มีเหตุผลที่จะพิจารณาตรรกะการประเมินบอร์ด - มันจะไม่ถูกเรียก) ผลที่ได้คือชนะแพ้หรือแพ้ การวาด. หากผลออกมาเสมอกันเกมนั้นยุติธรรมถ้าผลออกมาเสมอกันมันเป็นเกมที่ไม่ยุติธรรม หากต้องการขยายให้เพิ่มขึ้นเราได้รับ:

public Int64 Evaluate(Chessboard Board, int SearchDepth)
{
  foreach (ChessMove Move in Board.GetPossibleMoves())
    {
      Chessboard NewBoard = Board.MakeMove(Move);
      if (NewBoard.Checkmate()) return int.MaxValue;
      if (NewBoard.Draw()) return 0;
      if (SearchDepth == 0) return NewBoard.Score();
      return -Evaluate(NewBoard, SearchDepth - 1);
    }
}

โปรดทราบว่าคอมไพเลอร์จะไม่สามารถตระหนักได้ว่า Chessboard.Score () เป็นโค้ดที่ตายแล้ว ความรู้เกี่ยวกับกฎของหมากรุกช่วยให้มนุษย์เราสามารถเข้าใจสิ่งนี้ได้ แต่คุณต้องรู้ว่า MakeMove ไม่สามารถเพิ่มจำนวนชิ้นได้และ Chessboard.Draw () จะกลับมาจริงถ้าจำนวนชิ้นนั้นคงที่นานเกินไป .

โปรดทราบว่าความลึกของการค้นหาอยู่ในการเคลื่อนไหวครึ่งหนึ่งไม่ใช่การเคลื่อนไหวทั้งหมด นี่เป็นเรื่องปกติสำหรับชุดคำสั่ง AI นี้เนื่องจากเป็นชุดคำสั่ง O (x ^ n) - การเพิ่มการค้นหาอีกหนึ่งครั้งมีผลกระทบอย่างมากต่อระยะเวลาที่ใช้ในการเรียกใช้


8
คุณคิดว่าอัลกอริทึมการตรวจสอบจะต้องทำการคำนวณ ความผิดพลาดทั่วไป! ไม่คุณไม่ต้องคิดอะไรเกี่ยวกับการทำงานของตัวตรวจสอบมิฉะนั้นคุณจะไม่สามารถปฏิเสธการมีอยู่ของมันได้
กราฟิลส์

6
คำถามจะขอหลักฐานว่ามันเป็นไปไม่ได้ที่จะตรวจพบโค้ดที่ตายแล้ว โพสต์ของคุณมีตัวอย่างของกรณีที่คุณสงสัยว่าเป็นการยากที่จะตรวจพบโค้ดที่ตายแล้ว นั่นไม่ใช่คำตอบของคำถามในมือ
David Richerby

2
@ LorenPechtel ฉันไม่รู้ แต่นั่นไม่ใช่ข้อพิสูจน์ ดูที่นี่ด้วย; ตัวอย่างที่ชัดเจนของความเข้าใจผิดของคุณ
Raphael

3
ถ้ามันช่วยได้ลองคิดดูว่าในทางทฤษฎีแล้วไม่มีอะไรที่จะหยุดยั้งไม่ให้ใครบางคนวิ่งคอมไพเลอร์ของพวกเขานานกว่าอายุขัยของจักรวาล ข้อ จำกัด เพียงอย่างเดียวคือการปฏิบัติจริง ปัญหาที่ตัดสินใจได้เป็นปัญหาที่ตัดสินใจได้แม้ว่าจะอยู่ในคลาสที่ซับซ้อน
นามแฝง

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

-3

ฉันคิดว่าในหลักสูตรคอมพิวเตอร์ความคิดเกี่ยวกับรหัสตายตัวน่าสนใจในบริบทของการทำความเข้าใจความแตกต่างระหว่างเวลาคอมไพล์และเวลารัน!

คอมไพเลอร์สามารถกำหนดได้ว่าคุณได้รับรหัสที่ไม่สามารถข้ามผ่านสถานการณ์การคอมไพล์ได้ แต่ไม่สามารถทำได้ในขณะรันไทม์ while-loop ที่เรียบง่ายพร้อมอินพุตผู้ใช้สำหรับการทดสอบการแบ่งลูปแสดงว่า

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

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


1
คำถามถามเพื่อพิสูจน์ว่ามันเป็นไปไม่ได้ที่จะตรวจพบรหัสที่ตาย คุณยังไม่ได้ตอบคำถามนั้น
David Richerby

นอกจากนี้การยืนยันของคุณว่า "คอมไพเลอร์สามารถกำหนดได้ว่าคุณได้รับรหัสที่ไม่สามารถข้ามเวลาสถานการณ์การคอมไพล์ได้" ไม่ถูกต้องและขัดแย้งโดยตรงกับสิ่งที่คำถามขอให้คุณพิสูจน์
David Richerby

@ David Richerby ฉันคิดว่าคุณอาจเข้าใจผิดฉัน ฉันไม่ได้แนะนำว่าการตรวจสอบเวลาคอมไพล์สามารถค้นหารหัสที่ตายแล้วทั้งหมดไม่ได้แน่นอน ฉันแนะนำว่ามีเซตย่อยของเซตของรหัสตายทั้งหมดที่มองเห็นได้ในเวลารวบรวม ถ้าฉันเขียน: if (true == false) {print ("something");} คำสั่งการพิมพ์นั้นจะมองเห็นได้ในเวลารวบรวมเพื่อเป็นรหัสที่ตาย คุณไม่เห็นด้วยหรือไม่ว่านี่เป็นตัวอย่างการยืนยันของคุณ?
dwoz

แน่นอนว่าคุณสามารถกำหนดบางรหัสตาย แต่ถ้าคุณจะพูดว่า "กำหนดเมื่อ [คุณมีรหัสตายตัว]" โดยไม่มีคุณสมบัติดังนั้นสำหรับฉันหมายความว่าค้นหารหัสที่ตายแล้วทั้งหมดไม่ใช่แค่บางส่วนเท่านั้น
David Richerby
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.