ทำไมเครื่องหมายอัฒภาคและจุลภาคสลับกันเป็นลูป


49

ในหลายภาษา (รายการกว้างจาก C ถึง JavaScript):

  • ,คั่นด้วยจุลภาคคั่น (เช่นfunc(a, b, c)) ขณะที่
  • อัฒภาค;แยกคำแนะนำตามลำดับ (เช่นinstruction1; instruction2; instruction3)

เหตุใดการทำแผนที่นี้จึงย้อนกลับเป็นภาษาเดียวกันสำหรับfor loops :

for ( init1, init2; condition; inc1, inc2 )
{
    instruction1;
    instruction2;
}

แทน (สิ่งที่ดูเป็นธรรมชาติสำหรับฉัน)

for ( init1; init2, condition, inc1; inc2 )
{
    instruction1;
    instruction2;
}

?

แน่นอนว่าforเป็น (ปกติ) ไม่ทำงาน แต่ข้อโต้แย้ง (เช่นinit, condition, increment) ทำงานมากขึ้นเช่นการขัดแย้งของฟังก์ชั่นกว่าลำดับของคำแนะนำ

มันเป็นเพราะเหตุผลทางประวัติศาสตร์ / การประชุมหรือมีเหตุผลที่ดีสำหรับการแลกเปลี่ยน,และ;ในลูป?


1
(โพสต์ f1rst ของฉันที่นี่ฉันไม่แน่ใจว่าคำถามนี้เป็นของโปรแกรมเมอร์หรือดังนั้นจึงสามารถโยกย้ายหากจำเป็น)
Piotr Migdal

8
นี่คือโพสต์โปรแกรมเมอร์อย่างแน่นอน ยินดีต้อนรับ! :-)
Martijn Pieters

1
"ทำไมไม่" จะให้คำตอบ - โดยมีคำตอบเดียวกัน - "เพราะมีคนต้องการให้เลือกและนั่นคือตัวเลือกที่พวกเขาทำ" เหมือนกับ "ทำไมพวกเขาเลือก" {"และ"} "และตัวเลือกอื่น 1,000 รายการ พวกเขาทำ - "เพราะ"
mattnz

2
@mattnz คำถามเกี่ยวกับความสอดคล้อง (ไม่ใช่ "ทำไมเราจึงใช้;ไม่ได้|" (หรือทำไมเราจึงใช้ 'อื่น' ไม่ใช่ 'อย่างอื่น' )) ซึ่งไม่ใช่กรณีของภาษาหนึ่ง แต่เป็นจำนวนมาก คำตอบที่ว่า "มันถูกสร้างขึ้นใน C เป็นชวเลขในขณะที่วนรอบ (และหลายงบสำหรับ inc ถูกคิดในภายหลังเท่านั้น) และผู้คนไม่ต้องการเปลี่ยนมันเพื่อหลีกเลี่ยงการระคายเคืองของโปรแกรมเมอร์" จะดีอย่างสมบูรณ์
Piotr Migdal

ฉันจำการอ่านได้ - ในภาษา K&R - ว่าผู้ประกอบการจุลภาคถูกเพิ่มเข้าไปในภาษาเพื่อให้สามารถเริ่มต้นตัวแปรได้มากกว่าหนึ่งตัวแปรในการเริ่มต้นของคำสั่ง for
zwol

คำตอบ:


18

เหตุใดในภาษาเดียวกันจึงมีการสลับการจับคู่ดังกล่าวเป็นวนซ้ำ

ในทางเทคนิคการทำแผนที่จะไม่ "กลับรายการ"

  • สิ่งที่คั่นด้วยเครื่องหมายจุลภาคไม่ใช่พารามิเตอร์ ใน (อย่างน้อย) C ++ และ Java พวกเขาสามารถประกาศดังนั้นพวกเขาจึงไม่ได้แสดงออก
  • สิ่งที่คั่นด้วยเครื่องหมายอัฒภาคไม่ได้เป็นเพียงคำสั่งเดียว

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

ดังนั้นทำไมไม่ทำอย่างอื่นรอบ ๆ ?

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

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


เป็นเพราะเหตุผลทางประวัติศาสตร์ / การประชุม

ฉันไม่ได้ตระหนักถึงภาษาใด ๆ ก่อนที่ C ที่ใช้ไวยากรณ์เหมือน C สำหรับ "สำหรับ" ลูป:

  • Donal Fellows ตั้งข้อสังเกตว่า BCPL และ B ไม่มีโครงสร้างที่เทียบเท่า

  • FORTRAN, COBOL และ Algol-60 (และ Pascal) มีความหมายน้อยกว่าและมีไวยากรณ์ที่ไม่เหมือนกับ C "สำหรับ" ไวยากรณ์

แต่ภาษาอย่าง C, C ++ และ Java ที่มาหลังจาก C ทั้งหมดยืมไวยากรณ์ "สำหรับ" อย่างชัดเจนจาก C


ดังนั้นปรัชญาของ ( ,vs ;) คือ (อ่อนแอลงเมื่อเทียบกับการแตกที่แข็งแกร่งขึ้น) แทนที่จะเป็น สำหรับฉันยังไม่ชัดเจนว่าการขัดแย้งหรือข้อความสั่งต้องมีการแบ่งที่ชัดเจนขึ้นหรือไม่ (เช่นในหลายกรณีสำหรับลำดับของข้อความการหยุดพักจะมีความหมายโดยนัย (ดูเช่น JavaScript (เช่นi++[line break]j++))) แต่อย่างน้อยตอนนี้ฉันเข้าใจแล้วว่าทำไม ไม่ใช่ "ตรงกันข้ามอย่างเห็นได้ชัด"
Piotr Migdal

@PiotrMigdal เครื่องหมายจุลภาคเป็นตัวคั่นจะป้องกันการใช้ตัวถูกดำเนินการของเครื่องหมายจุลภาคและอาจบ่งบอกถึงองค์ประกอบของการ for loop เป็นคำสั่งมากกว่าการแสดงออก สิ่งนี้มีนัยสำคัญ

ความคิดเห็นล่าสุดทำให้ฉันอยากรู้ว่า BCPL ทำอะไร แต่เห็นได้ชัดว่ามีFOR i = e1 TO e2 BY e3 DO c(e1..e3 นิพจน์คำสั่ง c) ซึ่งคล้ายกับไวยากรณ์พื้นฐานของ BASIC ที่มา
CVn

1
@PiotrMigdal - "ปรัชญา" คือสิ่งที่ K&R และส่วนที่เหลือกำลังคิดย้อนกลับไปในปี 1970 ฉันไม่คิดว่ามันจะเป็นความคิดที่คุณจินตนาการ (พวกเขาพยายามใช้ภาษา "ระดับสูงกว่า" เพื่อหลีกเลี่ยงการเขียนซอฟต์แวร์สวิทช์โทรศัพท์ในแอสเซมเบลอร์)
สตีเฟนซี

ฉันเพิ่งตรวจสอบ; forไวยากรณ์ได้รับการแนะนำใน C (มันไม่ได้อยู่ในBหรือ BCPL)
Donal Fellows

60

เราเขียนลูปเช่น:

 for(x = 0; x < 10; x++)

ภาษาอาจถูกกำหนดไว้เพื่อให้ลูปดูเหมือน:

 for(x = 0, x < 10, x++)

อย่างไรก็ตามคิดถึงลูปเดียวกันที่นำมาใช้โดยใช้ลูป while:

 x = 0;
 while(x < 10)
 {
     x++;
 }

ขอให้สังเกตว่าx=0และx++เป็นงบสิ้นสุดลงด้วยเครื่องหมายอัฒภาค พวกเขาไม่ได้แสดงออกเช่นคุณจะมีในการเรียกใช้ฟังก์ชั่น ใช้เครื่องหมายอัฒภาคเพื่อคั่นคำสั่งและเนื่องจากสองในสามองค์ประกอบใน for for loop เป็นข้อความนั่นคือสิ่งที่ใช้ในนั้น ห่วงสำหรับเป็นเพียงทางลัดสำหรับวงในขณะนั้น

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

นอกจากนี้ความจริงที่ว่าคุณสามารถใช้เครื่องหมายจุลภาคเพื่อมีหลายคำสั่งในการวนรอบเป็นจริงสิ่งที่คุณสามารถทำได้นอกวง

x = 0, y= 3;

เป็นคำสั่งที่สมบูรณ์แบบแม้จะอยู่นอกวง for ฉันไม่รู้ว่าใช้งานได้จริงนอกวง แต่ประเด็นก็คือว่าจุลภาคแบ่งงบเสมอ; มันไม่ใช่คุณสมบัติพิเศษของ for for loop


แน่นอนฉันเข้าใจว่า "ขณะที่" ลูปนั้นเป็น "พื้นฐานมากกว่า" แต่ "สัญกรณ์สั้น ๆ " เช่นนี้ไม่สมเหตุสมผล (อย่างน้อยสำหรับฉัน) อย่างที่คุณสามารถเริ่มต้นด้วยx = 0; y = 0;และ (ภายในวงเล็บปีกกา) x++; y++;...
Piotr Migdal

2
@PiotrMigdal โอ้คุณทำได้ ประเด็นของฉันคือชิ้นส่วนภายในสำหรับลูปเป็นข้อความ (ซึ่งคั่นด้วยเครื่องหมายอัฒภาค) ไม่ใช่นิพจน์ (ซึ่งคั่นด้วยเครื่องหมายจุลภาค)
Winston Ewert

1
ฉันได้รับความแตกต่างเพียงสำหรับฉัน;เป็นธรรมชาติสำหรับลำดับของงบไม่จำเป็นต้องแยกงบใด ๆ (ดังนั้นมันเป็นเพียงแค่ที่รสนิยมแตกต่างกันอย่างไร) และในการประชุมหนึ่งในปัจจุบันบางครั้งจบลงด้วยการแยกลำดับของงบด้วยเครื่องหมายจุลภาคแล้ว ...
Piotr Migdal

3
@PiotrMigdal สมาชิกของ structs / unions ถูกคั่นด้วยเครื่องหมายอัฒภาค แต่สิ่งเหล่านี้ไม่ได้เรียงตามลำดับ ดังนั้นจึงไม่ได้ จำกัด อยู่เพียงลำดับของการใช้งานเท่านั้น ในตอนท้ายของวันไวยากรณ์จะลงมาเพื่อลิ้มรส
Winston Ewert

ฉันไม่รู้ว่าใช้งานได้จริงนอกวง for --- --- เกี่ยวกับ(foo)?bar++, qux++:bletch--- ที่คุณต้องการให้?:นิพจน์ทำสองสิ่งมากกว่าแค่อันเดียว ส่งคืนค่าถ้าfooเป็นจริงquxแต่ทั้งสองbarและquxเพิ่มขึ้น

15

ใน C และ C ++ นี่คือโอเปอเรเตอร์คอมม่าไม่ใช่แค่คอมมา

ไวยากรณ์ของการforวนซ้ำนั้นเป็นอย่างไร

for ([pre-expression]; [terminate-condition]; [increment-expression]) body-expression

ในกรณีที่มีคำถามของคุณ:

pre-expression -> init1, init2
terminate-condition -> condition
increment-expression -> inc1, inc2

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

ในระยะสั้น;หมายถึงจุดสิ้นสุดของคำสั่ง ห่วงคือคำหลักตามด้วยรายการของงบตัวเลือกที่ล้อมรอบด้วยfor ()คำสั่งเครื่องหมายจุลภาคอนุญาตให้ใช้,ในคำสั่งเดียว


3
สำหรับห่วงคือชุดของการแสดงออกคั่นด้วยเครื่องหมายอัฒภาค คำสั่งสามารถมีได้มากกว่านิพจน์ - หนึ่งคำสั่งไม่สามารถส่งคำสั่ง case หรือถ้าคำสั่งเป็นส่วนลูป มันมีความหมายสำคัญที่จะบอกว่าองค์ประกอบของ for loop นั้นเป็น statement เมื่อมีคนดูที่รูปแบบ bnf ของ for for loop

@MichaelT: แต่ใน C ++ ไวยากรณ์ของforลูปจะอนุญาตให้มีการประกาศ (การประกาศ) เป็นส่วนแรกอย่างชัดเจน (C ++ อนุญาตการประกาศ mid-function เมื่อเทียบกับรุ่นก่อน C89) คุณไม่สามารถสรุปข้อความดังกล่าวข้ามภาษาได้แม้จะเป็น 2 ภาษาใกล้เคียงกับ C และ C ++
MSalters

@MichaelT คุณพลาดส่วน 'is like like' หรือไม่?
James

@James คุณสามารถหลีกเลี่ยง "สิ่งที่ชอบ" โดยใช้ BNF จริงของfor ( {<expression>}? ; {<expression>}? ; {<expression>}? ) <statement>สำหรับCและfor ( for-init-statement; conditionopt ; expressionopt ) statementสำหรับC ++ --- ว่า '' ไม่เพียงบ่งบอกถึงคำสั่งยกเลิก สำหรับห่วงไม่ได้ตามด้วยคำสั่งที่อยู่ใน ()

8

ไม่มีการพลิกกลับแนวคิด

เครื่องหมายอัฒภาคใน C แสดงถึงหน่วยงานที่สำคัญมากกว่าเครื่องหมายจุลภาค พวกเขาแยกงบและการประกาศ

เขตการปกครองที่สำคัญในการวนรอบคือว่ามีสามนิพจน์ (หรือการประกาศและสองนิพจน์) และเนื้อความ

เครื่องหมายจุลภาคที่คุณเห็นใน C สำหรับลูปไม่ได้เป็นส่วนหนึ่งของไวยากรณ์ของ for loop โดยเฉพาะ พวกเขาเป็นเพียงอาการของผู้ประกอบการจุลภาค

เครื่องหมายจุลภาคเป็นตัวคั่นหลักระหว่างอาร์กิวเมนต์ในการเรียกใช้ฟังก์ชันและระหว่างพารามิเตอร์ในการประกาศฟังก์ชัน แต่ไม่ใช้เครื่องหมายอัฒภาค for loop เป็นไวยากรณ์พิเศษ มันไม่เกี่ยวอะไรกับฟังก์ชั่นหรือการเรียกฟังก์ชั่น


2

อาจจะเป็นสิ่งที่เฉพาะเจาะจงสำหรับ C / C ++ แต่ฉันโพสต์คำตอบนี้เพราะไวยากรณ์ของ lagnuages ​​ที่คุณอธิบายส่วนใหญ่ได้รับอิทธิพลจาก C-Syntax

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

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

ในความเป็นจริงที่operator,ถูกสร้างขึ้นเพื่อทำสิ่งเดียวกันเช่นในคำนิยามรายชื่ออาร์กิวเมนต์และอื่น ๆ : มันได้รับการสร้างเพื่อแยกการแสดงออก - สิ่งที่สร้างประโยค,ไม่สามารถทำ สามารถแยกสิ่งที่กำหนดไว้ในมาตรฐานเท่านั้น

อย่างไรก็ตามอัฒภาคไม่แยก - มันยุติ และนี่คือสิ่งที่ทำให้เรากลับไปที่คำถามเดิม:

for (int a = 0, float b = 0.0f; a < 100 && b < 100.0f; a++, b += 1.0f)
    printf("%d: %f", a, b);

เครื่องหมายจุลภาคแยกการแสดงออกในสามส่วนวงในขณะที่เครื่องหมายอัฒภาคยุติส่วน (การเริ่มต้นสภาพหรือภายหลัง) ของการกำหนดวง

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


มีปัญหากับอาร์กิวเมนต์นี้ ในforคำสั่ง;สัญลักษณ์จะถูกใช้อย่างชัดเจนเป็นตัวคั่น มันแยก 3 ส่วนประโยคของคำแถลง ไม่มีอัฒภาคที่ 3 เพื่อ "ยุติ" รายการนิพจน์โปรเกรสซีฟ มันถูกยกเลิกโดยโทเค็นที่แตกต่างกัน )-
สตีเฟ่นซี

0

สำหรับฉันพวกเขาใช้ความหมายที่คล้ายกันน้อยกว่ากับความรู้สึกทางภาษาของพวกเขา เครื่องหมายจุลภาคใช้กับรายการและอัฒภาคที่มีส่วนต่าง ๆ มากขึ้น

ในfunc(a, b, c)เรามีรายการข้อโต้แย้ง

instruction1; instruction2; instruction3 อาจเป็นรายการ แต่เป็นรายการคำสั่งแยกต่างหากและเป็นอิสระ

ในขณะที่for ( init1, init2; condition; inc1, inc2 )เรามีสามส่วนแยกกัน - รายการของการเริ่มต้นเงื่อนไขและรายการของการแสดงออกที่เพิ่มขึ้น


0

วิธีที่ง่ายที่สุดในการดูคือ:

for(x = 0; x < 10; x++)

คือ:

for(
x = 0;
x < 10;
x++
)

กล่าวอีกนัยหนึ่ง x = 0 สิ่งเหล่านั้นจริงๆแล้วเป็นคำสั่ง / คำสั่งแทนที่จะเป็นพารามิเตอร์ คุณแทรกคำสั่งที่นั่น ดังนั้นพวกเขาจะถูกคั่นด้วยเครื่องหมายอัฒภาค

ในความเป็นจริงไม่มีทางที่พวกเขาคั่นด้วยเครื่องหมายจุลภาค เมื่อครั้งสุดท้ายที่คุณแทรกสิ่งต่าง ๆ เช่น x <10 เป็นพารามิเตอร์? คุณทำเช่นนั้นหากคุณต้องการคอมพิวเตอร์ x <10 ครั้งเดียวและใส่ผลลัพธ์ของการดำเนินการนั้นเป็นพารามิเตอร์ ดังนั้นในคอมม่าโลกคุณจะใส่ x <10 ถ้าคุณต้องการส่งผ่านค่าของ x <0 ไปยังฟังก์ชั่น

ที่นี่คุณระบุว่าโปรแกรมควรตรวจสอบ x <10 ทุกครั้งที่มีการวนซ้ำ นั่นคือคำสั่ง

x ++ เป็นอีกหนึ่งคำแนะนำอย่างแน่นอน

เหล่านี้คือคำแนะนำทั้งหมด ดังนั้นพวกเขาจะถูกคั่นด้วยลำไส้ใหญ่กึ่ง


มันไม่ใช่คำสั่ง มันคือการแสดงออกคั่นด้วยเครื่องหมายอัฒภาค คำสั่งนั้นแตกต่างอย่างสิ้นเชิง

x <10 อาจเป็นนิพจน์ (ซึ่งโดยปกติจะคั่นด้วยเครื่องหมายอัฒภาค x = 0 เป็นคำสั่ง / คำแนะนำอย่างแน่นอน
user4951

ดูที่bnf สำหรับ C - หากคำสั่ง for loop เป็นคำสั่งหนึ่งสามารถใช้คำสั่งอื่นเช่นคำอื่นfor switchหรือreturn ภายในคำจำกัดความลูป (เช่นfor(int i = 0; if(i > 1024) { return; } ; switch (i % 3) { case 0; case 1: i++; case 2: i++; } ) { ... }) --- คุณไม่สามารถทำได้ มันไม่ใช่คำสั่ง แต่จะถูกกำหนดเป็นfor ( {<expression>}? ; {<expression>}? ; {<expression>}? ) <statement>

แปลก. int i = 0 เป็นนิพจน์ทั้งหมด แต่เราทำมันเพื่อประกาศ int คือ i และกำหนด 0 ให้กับมัน (มันจะส่งกลับ 0 แต่เป็นผลข้างเคียงคุณไม่สามารถทำเพื่อ ({int i = 0; j = i}; j <0; ศาล << "Hello world") ทำได้หรือไม่หรือใช่ฉันคิดว่าคุณทำได้
user4951

1
@JimThio: คุณอาจไม่ทราบ แต่ "คำสั่ง" และ "การแสดงออก" มีความหมายที่แม่นยำมากในมาตรฐานภาษา int i = 0แน่นอนไม่ใช่การแสดงออก ชุดของกฎที่อธิบายถึงนิพจน์นั้นค่อนข้างซับซ้อนโดยพิจารณาว่าอะไรที่สามารถประกอบเป็นนิพจน์ได้ แต่โครงสร้างนั้นTYPE NAME = EXPRESSIONไม่ตรงกับกฎเหล่านั้น
MSalters
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.