ทำไมไวยากรณ์ที่ไม่ชัดเจนนั้นไม่ดี


30

ฉันเข้าใจว่าหากมีต้นไม้ 2 ต้นขึ้นไปทางซ้ายหรือทางขวาไวยากรณ์ก็ไม่ชัดเจน แต่ฉันไม่สามารถเข้าใจได้ว่าทำไมมันถึงแย่มากที่ทุกคนต้องการกำจัดมัน


1
ที่เกี่ยวข้อง แต่ไม่เหมือนกัน: softwareengineering.stackexchange.com/q/343872/206652 (ข้อจำกัดความรับผิดชอบ: ฉันเขียนคำตอบที่ยอมรับแล้ว)
marstato

ดูเพิ่มเติมที่: "การค้นหาไวยากรณ์ที่ชัดเจน "
Rob

1
รูปแบบที่ชัดเจนนั้นดีกว่าสำหรับการใช้งานจริงรูปแบบที่ไม่กำกวมใช้กฎจำนวนโปรดักชั่นที่น้อยกว่าจะสร้างต้นไม้ขนาดเล็กในที่สูง เครื่องมือส่วนใหญ่ให้ความสามารถในการแก้ไขความกำกวมอย่างชัดเจนจากไวยากรณ์ด้านข้าง
Grijesh Chauhan

3
"ทุกคนต้องการกำจัดมัน" นั่นไม่จริงเลย ในภาษาที่เกี่ยวข้องในเชิงพาณิชย์เป็นเรื่องปกติที่จะเห็นความคลุมเครือเพิ่มเมื่อภาษามีวิวัฒนาการ เช่น C ++ โดยเจตนาเพิ่มความคลุมเครือstd::vector<std::vector<int>>ในปี 2011 ซึ่งเคยเป็นช่องว่างระหว่าง>>ก่อน ความเข้าใจที่สำคัญคือภาษาเหล่านี้มีผู้ใช้มากกว่าผู้ขายจำนวนมากดังนั้นการแก้ไขความรำคาญเล็กน้อยสำหรับผู้ใช้แสดงให้เห็นถึงการทำงานมากโดยผู้ใช้งาน
MSalters

คำตอบ:


52

พิจารณาไวยากรณ์ต่อไปนี้สำหรับการแสดงออกทางคณิตศาสตร์:

XX+XXXXXX/Xvarconst
พิจารณานิพจน์ต่อไปนี้: - - ค่าของมันคืออะไร? ที่นี่มีสองต้นแยกวิเคราะห์เป็นไปได้:
abc

(X - X) - X ป้อนคำอธิบายรูปภาพที่นี่

ตามที่ด้านซ้ายเราควรตีความabcเป็น(ab)cซึ่งเป็นการตีความปกติ ตามหนึ่งทางด้านขวาที่เราควรจะตีความว่ามันเป็น- ( - ) = - B + Cซึ่งอาจจะไม่ใช่สิ่งที่ตั้งใจa(bc)=ab+c

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


ต้นไม้แจงสร้างขึ้นโดยใช้เครื่องกำเนิดไฟฟ้าต้นไม้ไวยากรณ์


12
@HIRAKMONDAL ความจริงที่ว่าไวยากรณ์ไม่ชัดเจนไม่ใช่ปัญหาจริง ปัญหาคือต้นไม้แยกวิเคราะห์สองต้นนั้นมีพฤติกรรมที่แตกต่างกัน หากภาษาของคุณมีไวยากรณ์ที่คลุมเครือ แต่การแยกวิเคราะห์ต้นไม้ทั้งหมดสำหรับการแสดงออกนั้นเทียบเท่ากันทางอรรถศาสตร์นั่นจะไม่เป็นปัญหา (เช่นใช้ตัวอย่าง Yuval และพิจารณากรณีที่ตัวดำเนินการเดียวของคุณ+)
บาคุริ

14
@Bakuriu สิ่งที่คุณพูดนั้นเป็นความจริง แต่ "ความหมายเชิงเทียบเท่า" นั้นเป็นคำสั่งที่สูง ตัวอย่างเช่นการคำนวณจุดลอยตัวนั้นไม่ได้เชื่อมโยงกันจริง ๆ ดังนั้นต้นไม้ "+" สองรายการจึงไม่เทียบเท่ากัน นอกจากนี้แม้ว่าคำตอบจะออกมาในลักษณะเดียวกันลำดับการประเมินที่ไม่ได้กำหนดนั้นสำคัญมากในภาษาที่นิพจน์สามารถมีผลข้างเคียงได้ ดังนั้นสิ่งที่คุณพูดนั้นเป็นความจริงทางเทคนิค แต่ในทางปฏิบัติมันเป็นเรื่องผิดปกติมากสำหรับความกำกวมของไวยากรณ์ที่จะไม่มีผลกระทบต่อการใช้ไวยากรณ์นั้น
Richard Rast

บางภาษาในปัจจุบันตรวจสอบจำนวนเต็มล้นในการเพิ่มเติมดังนั้นแม้ + b + c สำหรับจำนวนเต็มขึ้นอยู่กับลำดับของการประเมินผล
gnasher729

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

12

ในทางตรงกันข้ามกับคำตอบอื่น ๆ ที่มีอยู่ [ 1 , 2 ] มีแน่นอนด้านการประยุกต์ใช้เป็นที่คลุมเครือไวยากรณ์มีประโยชน์ ในด้านการประมวลผลภาษาธรรมชาติ (NLP) เมื่อคุณต้องการแยกวิเคราะห์ภาษาธรรมชาติ (NL) ด้วยไวยากรณ์ที่เป็นทางการคุณมีปัญหาว่า NL มีความคลุมเครือในระดับต่าง ๆ โดยเนื้อแท้ [ดัดแปลงจาก Koh18, ch. 6.4]:

  • ความมีชีวิตชีวาของวากยสัมพันธ์:

    ปีเตอร์ไล่ล่าชายในรถสปอร์ตสีแดง

    ปีเตอร์หรือชายในรถสปอร์ตสีแดงหรือไม่?

  • ความหมายที่กว้างขวาง:

    ปีเตอร์ไปที่ธนาคาร

    ธนาคารที่จะนั่งหรือธนาคารเพื่อถอนเงินจาก?

  • ความเป็นประโยชน์ในทางปฏิบัติ:

    ชายสองคนอุ้มกระเป๋าสองใบ

    พวกเขานำกระเป๋ามาด้วยกันหรือว่าแต่ละคนมีกระเป๋าสองใบ?

วิธีการที่แตกต่างกันสำหรับ NLP จัดการกับการประมวลผลโดยทั่วไปและโดยเฉพาะอย่างยิ่ง ambuigities เหล่านี้ ตัวอย่างเช่นไปป์ไลน์ของคุณอาจมีลักษณะดังนี้:

  1. แยกวิเคราะห์ NL กับไวยากรณ์ที่ไม่ชัดเจน
  2. สำหรับทุก AST ที่เกิดขึ้น: รันการสร้างโมเดลเพื่อสร้างความหมายเชิงความหมายที่คลุมเครือและเพื่อกำจัดความคลุมเครือทางไวยากรณ์ที่เป็นไปไม่ได้จากขั้นตอนที่ 1
  3. สำหรับทุกรุ่นที่เกิด: บันทึกไว้ในแคชของคุณ

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

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

หากคุณต้องการที่จะได้รับในมือของคุณสกปรกด้วย parsers ความสามารถในการส่งออกหลาย derivations ไวยากรณ์คลุมเครือมีลักษณะที่เป็นไวยากรณ์กรอบ นอกจากนี้ [Koh18, ch. 5] มีคำแนะนำเกี่ยวกับการแสดงสิ่งที่คล้ายกับท่อส่งของฉันด้านบน โปรดทราบว่าเนื่องจาก [Koh18] เป็นบันทึกการบรรยายจึงอาจไม่ใช่เรื่องง่ายที่จะเข้าใจด้วยตนเองหากไม่มีการบรรยาย


อ้างอิง

[Koh18]: Michael Kohlhase "การประมวลผลภาษาธรรมชาติที่ใช้ลอจิกภาคเรียนฤดูหนาว 2018/19 หมายเหตุการบรรยาย" URL: https://kwarc.info/teaching/LBS/notes.pdf URL คำอธิบายหลักสูตร: https://kwarc.info/courses/lbs/ (ภาษาเยอรมัน)

[Koh18, ch. 5]: ดูบทที่ 5, "การนำแฟรกเมนต์ไปใช้: กรอบไวยากรณ์และตรรกะ" ใน [Koh18]

[Koh18, ch. 6.4] ดูบทที่ 6.4 "บทบาทการคำนวณของความกำกวม" ใน [Koh18]


ขอบคุณตัน .. ฉันมีข้อสงสัยเดียวกันและคุณล้างมัน .. :)
HIRAK MONDAL

1
ไม่พูดถึงปัญหากับ ควายควายควายควายควาย ...สำหรับจำนวนที่เหมาะสมควาย
Hagen von Eitzen

คุณเขียนว่า“ ตรงกันข้าม” แต่ฉันเรียกสิ่งนี้ว่าอีกด้านหนึ่งของเหรียญจากสิ่งที่ฉันตอบ การแยกภาษาธรรมชาติด้วยไวยากรณ์ที่คลุมเครือของพวกเขานั้นยากที่ตัวแยกวิเคราะห์แบบดั้งเดิมไม่สามารถทำได้!
Davislor

1
@ComFreek ฉันควรจะแม่นยำมากขึ้นที่นี่ ดูสั้น ๆ ที่ GF (ขอบคุณสำหรับลิงค์!) แสดงให้เห็นว่ามันอ่านไวยากรณ์ที่ไม่มีบริบทที่มีสามส่วนขยาย (เช่นอนุญาตให้ reduplication) และส่งกลับรายการของการพิสูจน์ที่เป็นไปได้ทั้งหมด อัลกอรึทึมที่จะทำเช่นนั้นมีมาตั้งแต่ยุค 50 อย่างไรก็ตามความสามารถในการจัดการ CFG ทั่วไปอย่างสมบูรณ์หมายถึงการรันไทม์กรณีที่เลวร้ายที่สุดของคุณเกิดขึ้นและในทางปฏิบัติแม้เมื่อใช้ตัวแยกวิเคราะห์ทั่วไปเช่น GLL วิศวกรซอฟต์แวร์พยายามใช้ CFG ย่อยเช่น LL grammars ที่สามารถ แยกได้อย่างมีประสิทธิภาพมากขึ้น
Davislor

1
@ComFreek ดังนั้นจึงไม่ใช่ว่าคอมพิวเตอร์ไม่สามารถจัดการ CFG ได้ (แม้ว่าภาษาธรรมชาติไม่ใช่การแปลด้วยบริบทและการแปลด้วยเครื่องที่มีประโยชน์จริง ๆ ใช้เทคนิคที่แตกต่างกันโดยสิ้นเชิง) ถ้าคุณต้องการให้ parser จัดการกับความกำกวมนั่นจะตัดทอนทางลัดบางอย่างที่จะทำให้มีประสิทธิภาพมากขึ้น
Davislor

10

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

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


9

ไม่IF a THEN IF b THEN x ELSE yหมายความว่า

IF a THEN
    IF b THEN
        x
    ELSE
        y

หรือ

IF a THEN
    IF b THEN x
ELSE
    y

? AKA ปัญหาที่น่ากังวลอย่างอื่น


1
นี่เป็นตัวอย่างที่ดีที่แสดงให้เห็นว่าแม้กระทั่งไวยากรณ์ที่ไม่กำกวม (เช่นใน Java, C, C ++, ... ) ก็ช่วยให้ชัดเจน (!) ความคลุมเครือจากมุมมองของมนุษย์ แม้ว่าเราจะมีรูปแบบที่เป็นทางการและใช้งานได้ดี แต่ตอนนี้เรามีปัญหาการพัฒนา UX / ปราศจากข้อบกพร่องมากขึ้น
ComFreek

5

ใช้การแยกวิเคราะห์ที่น่ารำคาญที่สุดใน C ++ เช่น:

bar foo(foobar());

นี่เป็นการประกาศฟังก์ชั่นfooของประเภทbar(foobar())(พารามิเตอร์เป็นตัวชี้ฟังก์ชั่นกลับมาfoobar) หรือประกาศตัวแปรfooประเภทintและเริ่มต้นด้วยการเริ่มต้นเริ่มต้นfoobar?

นี่คือความแตกต่างในคอมไพเลอร์โดยสมมติว่าเป็นครั้งแรกเว้นแต่การแสดงออกภายในรายการพารามิเตอร์ไม่สามารถตีความได้ว่าเป็นประเภท

เมื่อคุณได้นิพจน์ที่คลุมเครือเช่นนั้นคอมไพเลอร์มี 2 ตัวเลือก

  1. สมมติว่านิพจน์นั้นได้รับมาโดยเฉพาะและเพิ่ม disambiguator ให้กับไวยากรณ์เพื่อให้ได้มาซึ่งการแสดงออกอื่น

  2. เกิดข้อผิดพลาดและต้องการแก้ความกำกวมด้วยวิธีใดวิธีหนึ่ง

สิ่งแรกอาจหลุดออกไปโดยธรรมชาติสิ่งที่สองคือต้องให้โปรแกรมเมอร์คอมไพเลอร์รู้เกี่ยวกับความคลุมเครือ

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


5

ฉันคิดว่าคำถามมีข้อสันนิษฐานที่ถูกต้องตามแนวเขตแดนเท่านั้น

ในชีวิตจริงมันเป็นเรื่องธรรมดาที่จะอยู่กับแกรมม่าที่คลุมเครือตราบใดที่พวกเขาไม่ได้พูดคลุมเครือเกินไป

ตัวอย่างเช่นหากคุณมองไปที่ไวยากรณ์ที่คอมไพล์ด้วย yacc (หรือคล้ายกันเช่น bison หรือ byacc) คุณจะพบว่ามีคำเตือนเล็กน้อยเกี่ยวกับ "N shift / reduct problems" เมื่อคุณคอมไพล์พวกเขา เมื่อ yacc พบการเปลี่ยนแปลง / ลดความขัดแย้งนั่นเป็นสัญญาณความกำกวมในไวยากรณ์

อย่างไรก็ตามกะ / ลดความขัดแย้งมักเป็นปัญหาเล็กน้อย ตัวแยกวิเคราะห์จะแก้ไขข้อขัดแย้งในความโปรดปรานของ "การเปลี่ยนแปลง" มากกว่าการลด ไวยากรณ์นั้นใช้ได้อย่างสมบูรณ์แบบหากเป็นสิ่งที่คุณต้องการ (และดูเหมือนว่าจะได้ผลในทางปฏิบัติอย่างสมบูรณ์แบบ)

โดยทั่วไปแล้วการเปลี่ยนแปลง / ลดความขัดแย้งเกิดขึ้นในกรณีในคำสั่งทั่วไปนี้ (ใช้ตัวพิมพ์ใหญ่สำหรับที่ไม่ใช่ขั้วและตัวพิมพ์เล็กสำหรับขั้ว):

A -> B | c
B -> a | c

เมื่อเราพบกcมีความกำกวม: เราควรแยกวิเคราะห์cโดยตรงในฐานะAหรือเราควรแยกมันเป็นกBซึ่งในทางกลับกันคือAอะไร? ในกรณีเช่นนี้ yacc และเช่นจะเลือกง่าย / เส้นทางที่สั้นและแยกcโดยตรงในฐานะที่เป็นAมากกว่าการไปc-> B-> Aเส้นทาง นี้อาจจะผิด แต่ถ้าเป็นเช่นนั้นก็อาจหมายความว่าคุณมีข้อผิดพลาดง่ายจริงๆในโรงเรียนมัธยมของคุณและคุณไม่ควรอนุญาตให้cตัวเลือกที่เป็นไปได้สำหรับAทุก

ตอนนี้ในทางตรงกันข้ามเราอาจมีบางอย่างที่มากกว่านี้:

A -> B | C
B -> a | c
C -> b | c

ตอนนี้เมื่อเราพบcว่าเรามีความขัดแย้งระหว่างว่าจะรักษาcเป็นหรือB Cมีโอกาสน้อยกว่าที่กลยุทธ์การแก้ไขข้อขัดแย้งอัตโนมัติจะเลือกสิ่งที่เราต้องการจริงๆ สิ่งเหล่านี้ไม่ใช่ "การเปลี่ยนแปลง" - ทั้งคู่เป็น "การลด" ดังนั้นนี่คือ "การลด / ลดความขัดแย้ง" (ซึ่งผู้ที่คุ้นเคยกับ yacc และโดยทั่วไปรับรู้ว่าเป็นปัญหาที่ใหญ่กว่าการกะ / ลดความขัดแย้ง)

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


ชายหวังว่าฉันจะมีคำอธิบายที่ยอดเยี่ยมของความขัดแย้งกะลด 5 เดือนที่ผ่านมา! ^^; +1
HotelCalifornia
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.