โครงสร้างการควบคุมทางเลือกใดที่มีประโยชน์ที่คุณรู้ [ปิด]


12

คำถามที่คล้ายกันถูกปิดใน SO

บางครั้งเมื่อเราเขียนโปรแกรมเราพบว่าโครงสร้างการควบคุมบางอย่างจะมีประโยชน์มากสำหรับเรา แต่ไม่สามารถใช้ได้โดยตรงในภาษาการเขียนโปรแกรมของเรา

โครงสร้างการควบคุมทางเลือกใดที่คุณคิดว่าเป็นวิธีที่มีประโยชน์ในการจัดระเบียบการคำนวณ

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

คุณสามารถสร้างไวยากรณ์ / ความหมายที่ปรารถนาไม่พร้อมใช้งานในขณะนี้หรืออ้างอิงโครงสร้างการควบคุมที่รู้จักน้อยในภาษาการเขียนโปรแกรมที่มีอยู่

รู้รอบควรให้แนวคิดสำหรับภาษาการเขียนโปรแกรมใหม่หรือปรับปรุงภาษาจริง

คิดว่านี่เป็นการระดมสมองดังนั้นโพสต์สิ่งที่คุณคิดว่าเป็นความคิดที่บ้า แต่มันสามารถทำงานได้ในบางสถานการณ์

มันเกี่ยวกับการเขียนโปรแกรมที่จำเป็น


1
ทำไมคำถามนี้ต้องเกี่ยวกับ "การเขียนโปรแกรมที่จำเป็น"?
missingfaktor

@missingfaktor: เนื่องจากโครงสร้างการควบคุมเป็นเรื่องเกี่ยวกับการเขียนโปรแกรมที่จำเป็น แน่นอนว่าปัญหาบางอย่างสามารถแก้ไขได้ด้วยวิธีการใช้งานหรือวิธีอื่น แต่กระบวนทัศน์อื่นไม่ได้วางโครงสร้างการควบคุมในศูนย์กลางของการพัฒนา แต่อย่างไรก็ตามคุณสามารถมีความคิดสร้างสรรค์
Maniero

3
ฉันจะแบ่งปันการจับคู่รูปแบบกับทหารเนื่องจากเป็นเรื่องทั่วไปมากกว่าที่คำสั่ง Case และ If-Thens แต่ถ้านี่ไม่ใช่โซน FP ฉันคิดว่านั่นเป็นเพียงการจับคู่รูปแบบสำหรับพวกเราที่เหลือ!
CodexArcanum

@CodexArcanum: การจับคู่รูปแบบเป็นโครงสร้างที่คล้ายกันกับโครงสร้างที่จำเป็น แท้จริงแล้วการจับคู่รูปแบบนั้นเป็นทางเลือกสำหรับโครงสร้างการควบคุมที่จำเป็น ไม่ต้องอาย ;-)
Maniero

การดูคำตอบทั้งหมดทำให้ฉันมีความสุขที่ไม่มีข้อเสนอใด ๆ ในชีวิตจริง (และหวังว่าจะไม่เป็นเช่นนั้น) ขออภัย :)
serg

คำตอบ:


14

ตกลงนี่เป็นคำถามที่สนุก

ฉันอยากจะมีนายพลอยู่elseครู่หนึ่งและเป็นห่วงเพราะเมื่อเงื่อนไขไม่เป็นจริงในการทดสอบครั้งแรก :

while (condition) {
    // process
}
else {
    // condition was never true
}

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


Python มีสิ่งนี้
Barry Brown

เฮ้! ในที่สุดทางเลือกที่แปลกประหลาดของ Python ที่ฉันเห็นด้วย! ;-)
Macneil

5
ไม่ได้ประโยคอื่นใน Python สำหรับ / ในขณะที่ลูปจะถูกดำเนินการหากลูปจบลงตามปกติซึ่งหมายความว่าลูปจะไม่ถูกยกเลิกผ่านคำสั่ง break หรือ return หรือข้อยกเว้น ในลูป clasuse อื่นจะถูกเรียกใช้งานหลังจากลำดับขององค์ประกอบที่วนลูปถูกใช้จนหมดและในขณะที่ลูปถูกเรียกใช้งานหลังจากเงื่อนไขลูปประเมินเป็น False เป็นครั้งแรก
Pillmuncher

4
มีคำขอให้เพิ่มwhile ... elseโครงสร้างตามที่ Macneil อธิบายไว้ใน PHP ฉันคิดว่ามันเป็นความคิดที่ดีเพราะ "นี่คือผลลัพธ์ / ไม่มีผลลัพธ์" เป็นสำนวนที่พบบ่อยพอสมควรในเว็บแอป
Dean Harding

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

10

ทำไมไม่บดคำตอบเล็ก ๆ น้อย ๆ เป็นหนึ่งเดียว?

while (expr) {

    // Executed every iteration, unless first{} is present.
    // May be explicitly called rest{} if you like first{} to come first.

    // Blocks may return results, and consequently be used in expressions.
    return expr;

} first {

    // Executed only on the first iteration.

} pre {

    // Executed before every iteration.

} post {

    // Executed after every iteration.

} catch (oops) {

    // All blocks are implicitly try{}ed if followed by a catch{}.

} finally {

    // Executes after the block completes, regardless of exceptions.

} else {

    // Executed if the loop body or rest{} never executes.

} never {

    // Executes only when a client is present.

} drop (bad, worse), // Explicitly ignore certain exceptions.
  until (expr);      // Here, have a post-body condition, too.

ไวยากรณ์การสร้างโฟลว์คอนโทรลควบคุมทั่วไปที่ขยายได้ในภาษาที่จำเป็นจะค่อนข้างมีประโยชน์และสนุกสนาน จนกว่าสิ่งนั้นจะปรากฏขึ้นเดาว่าฉันจะใช้ Lisp หรืออะไรซักอย่าง


5
ไม่มีประโยชน์สับสน ไม่สนุกสนานช้า
Josh K

2
@Josh K: ใช่คุณพูดถูก อะไรที่คุณคิดว่าฉันไม่เห็นด้วย? คำตอบนี้กัดลิ้นเพื่อไม่ให้หัวเราะ
Jon Purdy

ถ้ามันตั้งใจจะแดกดันมันก็ประสบความสำเร็จอย่างแน่นอน!
Josh K

11
+1 ทำให้ฉันหัวเราะ ต้องการส่วน "ระหว่าง" เพื่อให้โค้ดทำงานระหว่างการวนซ้ำ
Barry Brown

1
+1 แต่ก็ต้องการseventh { ... }เช่นกัน
j_random_hacker

7

โครงสร้างการควบคุมเป็นฟังก์ชั่น

ฉันต้องการfor, if, else, whileฯลฯ จะเป็นฟังก์ชั่นโครงสร้างไม่ได้พิเศษ

ฉันต้องการreturn, try/exceptและgotoจะเป็นอนุพันธ์ของต

แน่นอนว่าสิ่งนี้มีส่วนเกี่ยวข้องกับโครงสร้างการควบคุมเฉพาะน้อยกว่าและอื่น ๆ เกี่ยวกับวิธีที่คุณเห็นโครงสร้างการควบคุมโดยทั่วไปคือเมตาของโครงสร้างการควบคุม


2
ต่อเนื่องเป็นแนวคิดหนาสำหรับภาษาและมีเหตุผลที่ดีสำหรับพวกเขาออกจากหลายภาษา
David Thornley

ฉันไม่เห็นด้วย มีfor, if, elseและwhileฟังก์ชั่นที่ทำให้ผมสรุปว่าพารามิเตอร์ฟังก์ชันเหล่านั้นจะต้องมีการดำเนินการอย่างเฉื่อยชาในการสั่งซื้อที่จะประพฤติเช่นเดียวกับโครงสร้างเดิม การมีความสามารถในการทำแบบขี้เกียจจะดีมาก
ศิษย์ของ Dr. Wily

1
@ David: เพียงเพราะพวกเขามีไม่ได้หมายความว่าคุณต้องใช้พวกเขา โปรแกรมเมอร์ทั่วไปสามารถใช้สิ่งที่พวกเขาคุ้นเคยreturnยกเว้น ฯลฯ แต่ตอนนี้โปรแกรมเมอร์ผู้เชี่ยวชาญมีเครื่องมือเพิ่มเติมที่มีประสิทธิภาพในกล่องเครื่องมือของเขาหากจำเป็นต้องเกิดขึ้น นอกจากนี้ภาษาของ IMHO ไม่ควร "ถูกทำให้แย่ลง" ภาษาควรมีความสามารถในการสนับสนุนความเชี่ยวชาญที่เพิ่มขึ้นและการเติบโตของความรู้ CS
dietbuddha

1
@dietbuddha: (ต่อ) ฉันไม่ได้พูดว่าการต่อเนื่องไม่ดีฉันกำลังบอกว่ามันหนาและทำให้พวกมันใช้งานได้มีความหมายต่อภาษาเหมือนมีข้อยกเว้น นอกจากนี้การมีความต่อเนื่องอาจทำให้เกิดการเปลี่ยนแปลงในการที่คนใช้ภาษาเช่นเดียวกับข้อยกเว้นใน C ++ ภาษาที่รองรับการต่อเนื่องจะแตกต่างจากภาษาที่ไม่ดีทั้งในแง่ดีและไม่ดี
David Thornley

1
@ Steve314 - longjmp ไม่ได้ต่อเนื่องแม้ว่าจะมีความคล้ายคลึงกัน การบันทึกต่อเนื่องจะช่วยรักษาสถานะทั้งหมดไว้ (คนในท้องถิ่น, กลมและสแต็กทั้งหมด) longjmp บันทึกตัวชี้สแต็กดังนั้นถ้าคุณหลบหนีผ่านขอบเขตที่ใช้ setjmp คุณจะได้รับ segfault เนื่องจากเฟรมไม่มีอยู่อีกต่อไป ฉันเชื่อว่ายังมีข้อ จำกัด บางอย่างในตัวแปรที่ประหยัด
dietbuddha

6

บทความที่เชื่อมโยงแน่นอนได้รับมันถูกต้องเกี่ยวกับโดนัลด์ของ Knuth N + 2/1 ลูป แสดงเป็น C / C ++ / Java:

for (;;) {
  get next element;
  if (at the end) break;
  process the element;
}

สิ่งนี้มีประโยชน์สำหรับการอ่านบรรทัดหรืออักขระจากไฟล์ทดสอบว่าคุณถึง EOF แล้วทำการประมวลผล ฉันเคยเห็นรูปแบบfor(;;)..if(..)break;ปรากฏว่ามันเป็นสำนวนให้ฉัน (ก่อนที่ฉันจะอ่านบทความ Knuth ที่พิมพ์ซ้ำในโปรแกรม Literate Programmingหนังสือเล่มนี้เคยเป็น "wtf?")

Knuth แนะนำคำหลักloop/while/repeat:

loop:
  S;
while C:
  T;
repeat

ที่ไหนSและTเป็นผู้ถือสถานที่สำหรับชุดของคำสั่งเป็นศูนย์หรือมากกว่าและCเป็นเงื่อนไขบูลีน หากไม่มีSคำสั่งก็จะเป็นวงในขณะที่และถ้าไม่มีTคำสั่งแล้วมันจะเป็นวงทำ

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

ในบทความเดียวกัน Knuth แนะนำกลไกการส่งสัญญาณที่จะเป็นข้อยกเว้นในการขว้างปา / จับได้ในท้องถิ่น (เป็นทางเลือกแทนการใช้ goto)

สำหรับฉัน? ฉันหวังว่า Java สนับสนุนหางเพิ่มประสิทธิภาพการโทรเพื่อที่ฉันจะแสดงใด ๆโครงสร้างการควบคุมทั่วไปตามความจำเป็น


อัปเดต:ฉันลืมที่จะพูดถึงว่าโปรแกรมเมอร์ C / C ++ / Java จำนวนมากหลีกเลี่ยงปัญหานี้โดยใช้การกำหนดแบบฝังในเงื่อนไขwhile:

while ((c = getc(f)) != -1) {
   T;
}

การใช้คำศัพท์จากโครงสร้างของ Knuth สิ่งนี้สามารถใช้ได้เมื่อSและCสามารถรวมกันเป็นนิพจน์เดียวได้ บางคนเกลียดที่จะเห็นการมอบหมายที่ฝังอยู่ด้านบนในขณะที่คนอื่นเกลียดที่จะเห็นbreakในfor (;;)ด้านบน แต่เมื่อใดSและCไม่สามารถรวมกันได้เช่นเมื่อSมีหลาย statement for (;;)มันเป็นทางเลือกเดียวโดยไม่ต้องใช้รหัสซ้ำ อีกทางเลือกหนึ่งคือการทำซ้ำSรหัส:

S;
while (C) {
  T;
  S;
}

loop/while/repeatทางเลือกของ Knuth นั้นดูดีกว่ามาก


ลูปในขณะที่ทำซ้ำนั้นมีลักษณะเหมือนrepeat-untilลูปปาสกาล
Mason Wheeler

@ Mason: ความแตกต่างคือมีสองที่ที่คุณสามารถแทรก statement พร้อมเงื่อนไขของคุณไม่ใช่แค่ที่เดียว
Macneil

โอ้ฉันเห็นสิ่งที่เกิดขึ้น ใช่แล้วมันน่าสนใจ ...
Mason Wheeler

ANSI Basic มี a do while ... loop until- ทั้ง precondition และ postcondition เป็นทางเลือกและฉัน (ราง) จำได้ว่าใช้ทั้งสองในวงเดียว กลางสภาพของคุณมีของ exit when ...;Ada ข้อได้เปรียบที่สำคัญif ... break;คือคุณสามารถเขียนexit loopname when ...;เพื่อออกจากหลาย ๆ วง (แต่ไม่จำเป็นต้องทั้งหมด) ลูปซ้อนกันในครั้งเดียว อาจจะมองเห็นได้ชัดเจนกว่าตัวแบ่งเล็กน้อยเช่นกัน
Steve314

สิ่งที่ตลก Ada มีคุณสมบัติตรงตามนั้น
John R. Strohm

6

ภาษา BCPL มีvalueofนิพจน์ที่สามารถใช้เปลี่ยนลำดับของข้อความเป็นนิพจน์เดียว:

foo(a, b, valueof {some series of statements; resultis v});

ไหนsome series of statementsสามารถเป็นอะไรก็ได้และทั้งประเมินvalueofv

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

หากคุณสามารถใช้finalสำหรับตัวแปรที่จำเป็นคุณสามารถทำได้valueofใน Java โดยใช้คลาสภายในที่ไม่ระบุชื่อ:

foo(a, b, new Object(){String valueof(){
    String v ...; some series of statements; return v;}}.valueof());

1
GCC มีส่วนขยายสำหรับนี้ ({ statement1; statement2; ...; result-expr; })- ฉันเคยเห็นที่อื่นที่คล้ายกัน แต่ฉันจำไม่ได้ว่าที่ไหน น่าจะคัดลอกทั้งหมดจาก BCPL
Steve314

6
unless(condition) {
  // ...
}

ทำสิ่งเดียวกันกับ:

if(!condition) {
  // ...
}

repeat {
  // ...
} until(condition)

ทำสิ่งเดียวกันกับ:

do {
  // ...
} while(!condition)

คุณอาจต้องการที่จะไปชัด ...
duros

1
unlessหรือทับทิมก็มีไวยากรณ์ที่คล้ายกันสำหรับ
Josh K

2
ดูค่อนข้างจะเพรียวลม มีมากกว่าหนึ่งวิธีที่จะทำ

2
@ Steve314 คุณต้องใช้รูปแบบวงเล็บปีกกาที่ไม่ถูกต้อง ;-)
Orbling

1
@Orbling - ไม่เลย ทุกคนอื่นใช้สไตล์รั้งไม่ถูกต้อง
Steve314

5

ในบันทึกอื่นฉันต้องการดูการสนับสนุนที่ดีขึ้นสำหรับตัววนซ้ำในภาษาโปรแกรม โดยเฉพาะอย่างยิ่งสำหรับเมื่อคุณต้องการลงสองคอลเลกชันเป็นคู่ :

for (String s, Integer i : stringsSet, integersSet) {
    // use the pair (s, i)
}

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

หากทั้งสองชุดนั้นมีขนาดไม่เท่ากันก็สามารถโยนข้อยกเว้นหรือคุณอาจมีการelseวนลูปหลังจากสัญญาณมีความแตกต่างในขนาด

โดยธรรมชาติคุณสามารถพูดคุยเรื่องนี้เพื่อลดรายการสามรายการขึ้นไป


ปรับปรุง:ยังมีประโยชน์ที่จะทำผลิตภัณฑ์คาร์ทีเซียนระหว่าง iterables:

for (String s, Integer i : stringsSet * integersSet) {
    // use the pair (s, i), each s with each i
}

ซึ่งจะไม่มีอะไรมากไปกว่าลูปซ้อนกัน:

for (String s : stringsSet) {
    for (Integer i : integersSet) {
        // use the pair (s, i), each s with each i
    }
}

ฉันกังวลเล็กน้อยว่าระหว่างสองสัญลักษณ์ที่ฉันมีให้ที่นี่มีความแตกต่างของ O (n) และ O (n ^ 2) ในจำนวนคู่โดยมีการเปลี่ยนแปลงเพียงตัวเดียว


2
ใน Python มี zip และ zip_longest ทำเช่นนี้
Pillmuncher

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

1
ทั้งสองกรณีนี้ใน Scala: paste.pocoo.org/show/297429
missingfaktor

1
ในการอ้างอิงถึงผลิตภัณฑ์คาร์ทีเซียน: อีกครั้ง Python มีมัน for a, b, c in itertools.product(iter1, iter2, iter3):ให้ผลิตภัณฑ์คาร์ทีเซียนประเมินคุณอย่างขี้เกียจ นั่นอะไร? คุณต้องการวิธีเรียงสับเปลี่ยนและการรวมตัววนซ้ำที่กำหนดด้วยหรือไม่ itertools.permutations, itertools.combinations.
aaronasterling

1
Haskell เปอร์สเปคทีฟ: ใช้ "zipWith" สำหรับเคสแรกและ list comprehension หรือ List monad สำหรับวินาที เช่นเดียวกับ Python / Scala exmaples แต่ดูดีกว่า :)
LennyProgrammers

5

มีสิ่งที่เรียกว่า "ห่วงของ Dijkstra" (เรียกอีกอย่างว่า "ห่วงรักษาความปลอดภัยของ Dijkstra") มันถูกกำหนดไว้ในยามคำสั่งภาษา (GCL) คุณสามารถหาข้อมูลเกี่ยวกับมันบางไวยากรณ์และความหมายในข้างต้นวิกิพีเดียบทความที่ส่วนที่ 6 การทำซ้ำ: ทำ

ทุกวันนี้ฉันรู้ภาษาการเขียนโปรแกรมภาษาเดียวที่รองรับการควบคุมนี้โดยตรง มันคือOberon-07 (PDF, 70 KB) และสนับสนุน "Dijkstra's Loop" ในรูปแบบของคำสั่ง while ดูหัวข้อ 9.6 ในขณะที่งบใน PDF ข้างต้น

WHILE m > n DO m := m – n 
ELSIF n > m DO n := n – m 
END

PS นี่เป็นสำเนาคำตอบ SO ของฉัน


ดูเหมือนว่าตัวตรวจสอบโมเดล Spin ยังมีโครงสร้างนี้ด้วยความหมายที่เหมือนกันและไวยากรณ์ที่เหมือนกันโดยทั่วไป
j_random_hacker

4

การแสดงออกสไตล์ไอคอนด้วยการย้อนรอยในตัว

Python ได้รับประโยชน์จากเครื่องมือสร้างไอคอนจำนวนมาก - และทำงานได้ดีขึ้นโดยทั่วไป IMO และโดยหลักการแล้วการย้อนรอยเป็นเพียงข้อยกเว้น แต่มันคือความเรียบง่ายในการแสดงออกที่เทียบเท่ากับ ...

x = (a / b) else c;

การจัดการกรณีที่ล้มเหลวเช่นการหารด้วยศูนย์

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

ฉันมักจะคิดว่าพวกเขาควรจะมีการifแสดงออกโดยไม่มีส่วนอื่น - if (condition, success-value)ชนิดของสิ่งที่ย้อนกลับหากเงื่อนไขผลตอบแทนที่เป็นเท็จ - และวางการเปรียบเทียบที่แปลก

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


4

นี่เป็นเพียงแนวคิดและไวยากรณ์ทั่วไป:

if (cond)
   //do something
else (cond)
   //do something
also (cond)
   //do something
else
   //do something
end

เงื่อนไข ALSO จะได้รับการประเมินเสมอ ELSE ทำงานได้ตามปกติ

มันใช้ได้กับกรณีด้วย อาจเป็นวิธีที่ดีในการกำจัดคำสั่ง break:

case (exp)
   also (const)
      //do something
   else (const)
      //do something
   also (const)
      //do something
   else
      //do something
end

สามารถอ่านได้เป็น:

switch (exp)
   case (const)
      //do something
   case (const)
      //do something
      break
   case (const)
      //do something
   default
      //do something
end

ฉันไม่รู้ว่าสิ่งนี้มีประโยชน์หรือง่ายต่อการอ่าน แต่เป็นตัวอย่าง


3

สไตล์ที่ต่อเนื่องผ่านการคำนึงถึง แน่นอนว่าคุณต้องมีTail Call Optimizationเช่นกัน


1
ไม่ใช่แฟนตัวยงของเรื่องนี้และฉันไม่เชื่อว่ามันเป็น "โครงสร้างการควบคุม" แต่เป็นกลุ่มอาคารในภาษาที่ใช้งานได้และรูปแบบการเขียนโปรแกรม Node.js ดูเหมือนว่าค่อนข้างติดอยู่กับมันแม้ว่า
Josh K

1
แน่นอนมันเป็นโครงสร้างการควบคุม มันไม่ใช่คำที่มาพร้อมกับคำหลักเช่น 'if' หรือ 'for' แต่เป็นรูปแบบการไหลของการควบคุมโครงสร้าง (ดังนั้นโครงสร้างการควบคุม) มันยังใช้กับเบื้องหลังโดยคอมไพเลอร์มากมาย และไม่ จำกัด เฉพาะ FLs เช่นกัน คุณต้องการฟังก์ชั่นเป็นวัตถุชั้นหนึ่ง
Pillmuncher

1
คุณได้รับการเพิ่มประสิทธิภาพการโทรหางใน C และ C ++ วันนี้ แต่ IMO มันพลาดจุด ประเด็นก็คือว่ามันเป็นเพิ่มประสิทธิภาพ ใน Scheme การเรียกแบบหางที่แท้จริงนั้นชัดเจน ใน C ++ โดยเฉพาะอย่างยิ่งหลายสิ่งหลายอย่างอาจหมายถึงการโทรหางของคุณไม่ใช่การโทรหาง และสแต็คล้นหมายความว่าแอปของคุณเสีย IMO ควรมีบางสิ่งบางอย่างเช่นgoto return ...;คำสั่งทำให้มีความตั้งใจที่จะโทรหางอย่างชัดเจนดังนั้นหากคอมไพเลอร์ไม่สามารถทำซ้ำมันเป็นข้อผิดพลาด
Steve314

1
@ Macneil - ที่ฉันรู้แน่นอนการเพิ่มประสิทธิภาพการโทรหางจะทำใน GCC, Clang และ Visual C ++ GCC มีการแปลงที่ซับซ้อนมากขึ้นตั้งแต่การเรียกซ้ำจนถึงการวนซ้ำซึ่งสามารถจัดการกับหลายกรณีที่ไม่ได้เรียกซ้ำแบบหาง แต่มีอะไรผิดพลาดมากมาย ส่งต่อตัวชี้ไปยังตัวแปรโลคัลในการเรียกใช้หางและไม่สามารถกำจัดเฟรมสแต็กได้เนื่องจากตัวแปรต้องมีชีวิตอยู่ ใน C ++, destructors ตัวแปรโลคัลจะเกิดขึ้นตามปกติหลังจากการเรียก "tail" ส่งคืนซึ่งหมายความว่าไม่ใช่การเรียก tail ทั้งหมด
Steve314

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

3

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

branch foo(data, to, be, processed){
    //code
    return [resulting, data]
}

เมื่อสาขาถูกเรียกมันจะส่งคืนหมายเลขอ้างอิงทันที

handle=foo(here, is, some, data)

หมายเลขอ้างอิงสามารถใช้เพื่อตรวจสอบว่างานเสร็จสมบูรณ์หรือไม่

handle.finished() //True if the execution is complete

หากมีการร้องขอผลลัพธ์ก่อนที่การดำเนินการจะเสร็จสมบูรณ์เธรดหลักจะรอ

[result, storage]=handle.result()

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


มีลักษณะที่ Cilk ก็เป็นส่วนขยายที่สะอาดมากและเรียบง่ายของ C: en.wikipedia.org/wiki/Cilk ฉันไม่รู้ว่ามันมีการhandle.finished()ทดสอบหรือไม่spawnและsyncเป็นสิ่งที่คุณต้องการสำหรับ 90% ของการเขียนโปรแกรมแบบขนาน
j_random_hacker

3
if (cond)
   //do something
else (cond)
   //do something
else (cond)
   //do something
first
   //do something
then
   //do something
else (cond)
   //do something
else
   //do something
end

FIRST และบล็อก THEN นั้นจะทำงานหากมีการประเมินเงื่อนไขใด ๆ 3 ข้อเป็นจริง FIRST block จะทำงานก่อนที่บล็อกแบบมีเงื่อนไขและ THEN จะทำงานหลังจากบล็อกแบบมีเงื่อนไขทำงานแล้ว

เงื่อนไขอื่น ๆ หรือการเขียนขั้นสุดท้ายต่อไปนี้คำสั่ง FIRST และ THEN นั้นเป็นอิสระจากบล็อกเหล่านี้

มันสามารถอ่านเป็น:

if (cond)
   first()
   //do something
   then()
else (cond)
   first()
   //do something
   then()
else (cond)
   first()
   //do something
   then()
else (cond)
   //do something
else
   //do something
end


function first()
   //do something
return
function then()
   //do something
return

ฟังก์ชั่นเหล่านี้เป็นเพียงรูปแบบการอ่าน พวกเขาจะไม่สร้างขอบเขต มันเป็นเหมือน gosub / return จาก Basic

ประโยชน์และความสามารถในการอ่านเป็นเรื่องของการอภิปราย


2

บางครั้งฉันพบว่าตัวเองกำลังเขียนลูปที่ต้องทำสิ่งที่แตกต่างในระหว่างการทำซ้ำครั้งแรก ตัวอย่างเช่นการแสดงแท็ก <th> แทนแท็ก <td>

ฉันจัดการกับสถานการณ์นี้ด้วยธงบูลีน บางสิ่งเช่นนี้

first = true

while (some_condition)
    if (first)
        do_something
        first = false
    else
        do_something_else

ดูเหมือนว่าโง่ที่จะตรวจสอบค่าของfirstการวนซ้ำทุกครั้งเมื่อมันเป็นเท็จเกือบตลอดเวลา

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


คำถาม SO มีความคิดที่คล้ายกัน แต่มีตัวดำเนินการ "แล้ว" เพื่อใช้กับค่า ด้วยวิธีนี้คุณอาจไม่มีรหัสซ้ำ เช่นprint(out, first "<th>" then "<td>")
Macneil

1
วิธีที่ดีกว่าคือเริ่มการทำซ้ำ +1
Josh K

1
กรณีทั่วไปกำลังวนลูปด้วยระหว่างการจัดการตัวอย่างเช่นการแสดงรายการด้วยตัวคั่นจุลภาค อย่างเคร่งครัดนั่นคือif (!first) gimme-a-comma ();แต่สิ่งเดียวกันมาก แม้ว่าฉันจะคัดค้าน แต่ถ้าคุณสรุปมันอย่างเหมาะสมคุณจะต้องจบด้วยสิ่งต่าง ๆ เช่นวิธีการรวมสตริงของ Python แต่บ่อยครั้งที่คุณต้องการรูปแบบพื้นฐานการวนซ้ำพื้นฐานไม่จำเป็นต้องถูกเขียนใหม่บ่อยครั้ง
Steve314

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

1
@Barry Brown: การยกเลิกการวนซ้ำครั้งแรกของลูปอาจจะเร็วกว่าการตรวจสอบธงบูลีนหรือไม่ก็ได้ ตัวพยากรณ์สาขาที่เหมาะสมจะคาดเดาผิดที่เลวร้ายที่สุดในการทำซ้ำครั้งที่ 2 ฉันคาดการณ์ :) ฉันต้องการใช้if (!first)และให้คอมไพเลอร์ที่ปรับให้เหมาะสมตัดสินใจว่าตัวลูปมีขนาดเล็กพอที่การคลี่คลายและกำจัดfirstได้หรือไม่
j_random_hacker

1

[คัดลอกมาจากคำตอบของฉันเองใน stackoverflow]


ignoring - เพื่อละเว้นข้อยกเว้นที่เกิดขึ้นในบล็อกของรหัส

try {
  foo()
} catch {
  case ex: SomeException => /* ignore */
  case ex: SomeOtherException => /* ignore */
}

ด้วยโครงสร้างการควบคุมที่ไม่สนใจคุณสามารถเขียนได้กระชับและอ่านง่ายขึ้นเป็น:

ignoring(classOf[SomeException], classOf[SomeOtherException]) {
  foo()
}

[Scala ให้สิ่งนี้ (และโครงสร้างการควบคุมการจัดการข้อยกเว้นอื่น ๆ อีกมากมาย) ในไลบรารีมาตรฐานของมันในแพ็คเกจ util.control ]


4
ข้อยกเว้นไม่ควรเพิกเฉย
Josh K

1
ยกเว้นว่าในบริบทข้อยกเว้นอาจไม่ใช่ข้อผิดพลาด
Steve314

1
@Josh, @Steve: มีหลายกรณีที่คุณต้องการละเว้นข้อยกเว้น ดูหัวข้อนี้สำหรับบางกรณี
missingfaktor

ข้อยกเว้นคือการแจ้งเตือนว่ามีบางอย่างผิดปกติ try..catchบล็อกว่างเปล่าเป็นสิ่งหนึ่ง มันบังคับให้คุณรับรู้ข้อผิดพลาดและจงใจเพิกเฉย ในขณะที่การขว้างรหัสเป็นชิ้น ๆ ภายใต้การเพิกเฉยทั่วโลกสามารถนำไปสู่ปัญหาเมื่อข้อยกเว้นเหล่านั้นถูกโยนทิ้งไปรวมถึงพฤติกรรมการเขียนโปรแกรมที่ไม่ดี
Josh K

@Josh - เพียงแค่ลบสองความคิดเห็นเพราะฉันไม่ได้คิดว่าตรง - แต่ความหวังสูงสำหรับคนนี้ ถ้าข้อความนั้นเป็นโลกฉันอาจเห็นด้วย - แต่ดูเหมือนโครงสร้างบล็อกสำหรับฉัน IOW มันเหมือนtryบล็อกยกเว้นมันจะแสดงรายการข้อยกเว้นที่จับและไม่สนใจต่อไปแทนที่จะเป็นในภายหลัง นั่นอาจเป็นข้อได้เปรียบในการอ่าน - เช่นการแจ้งให้ผู้อ่านทราบว่าไฟล์ที่หายไปไม่ใช่ข้อผิดพลาดแม้แต่ก่อนที่พวกเขาจะเปิดการโทร
Steve314

1

แทน:

switch(myEnum) {
  case MyEnum.Val1: do1(); ...
  case MyEnum.Val2: do2(); ...
....

ใช้ Python หรือ C # ก็ได้เช่นกัน:

action = val2func[myEnum]
action()

Scala มีคุณสมบัติใหม่มากมาย

ในที่สุดภาษาเช่น Clojure สามารถขยายเพื่อให้การทำงานพิเศษ


1
C สามารถทำสิ่งนี้ได้เช่นกัน และปาสกาล ภาษา 70s / 80s / 90s เก่า ๆ อาเรย์ของฟังก์ชั่นกลายเป็นอาเรย์ของพอยน์เตอร์ของฟังก์ชั่น แต่นั่นไม่ใช่เรื่องใหญ่ ที่ ๆ มันจะง่ายขึ้นเมื่อคุณมีฟังก์ชั่นนิรนาม - คุณรู้เหมือนใน Lisp, ML, ...
Steve314

Steve314 - การแก้ไข - นี่คือตัวอย่างของพจนานุกรมที่แมปค่าใด ๆ กับฟังก์ชัน นี่คือสิ่งที่กลายเป็นสิ่งที่สะอาดกว่าสิ่งเล็กน้อยจาก 70s / 80s / 90s สามารถทำได้
งาน

1

ฉันมีสองแนวคิด

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

try {
    // Save something
} catch (Exception e) {
    // Something we do for all Exceptions
    catch (ProcessingException e) {
        // Something we do for all Processing exceptions
        catch (DBExcpetion e) {
            // DBExceptions are a subclass of ProcessingException
        }
        catch (BusinessRuleException e) {
            // BusinessRuleExceptions are also a subclass of ProcessingException
        }
    }
    // Something we do after specific sub class Exceptions
 }

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

Account a = getSavedAccount();
if (a == null) {
    a = getAccountFromSessionId();
}
if (a == null) {
    a = getAccountFromCookieId();
}
if (a == null) {
    a = createNewAccount();
}

ใน Javascript (ดี, ECMAScript, และอื่น ๆ ที่ฉันไม่คุ้นเคย) เนื่องจากค่าใด ๆ ที่สามารถประเมินเป็นเงื่อนไข||สามารถช่วยได้

var a = getAFromLocation1() || getAFromLocation2() || default;

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


Python ทำสิ่งที่ชอบ || ของคุณ การประเมินผล แต่เมื่อในที่สุดก็ได้รับx if c else yไวยากรณ์การแสดงออกตามเงื่อนไขของมันเหตุผลสำคัญที่เกิดขึ้นเป็นเพราะการแสดงออกจำนวนมากที่ใช้ความหมายเหล่านี้สำหรับ||และ&&มีรถม้าอย่างละเอียด IIRC กรณีทั่วไปคือค่า (เช่นศูนย์) ที่ถูกต้องสำหรับแอปพลิเคชันที่กำลังรับการปฏิบัติfalseดังนั้นจึงถูกยกเลิกเพื่อให้มีการใช้ทางเลือกที่ไม่ถูกต้องแทน อย่างไรก็ตาม - ดูคำตอบของฉัน WRT get1() else get2() else defaultการเขียนโปรแกรมภาษาไอคอนซึ่งจะมีการแสดงออกเช่น
Steve314

1

สวิตช์ทั่วไปได้กล่าวข้างต้น:

 switch(x){
  predicate1:
     dosomething();
  predicate2:
     dosomethingelse();
 }

ใน Haskell:

  switch' :: a -> [(a -> Bool, b)] -> b
  switch' a [] = undefined
  switch' a (f,b):xs = if f a
                     then b
                      else switch' a xs

0

ใน C # ฉันต้องการใช้ง่ายswitch () { ... }แต่ขยายได้ด้วยการแสดงออกดังกล่าว:

switch (value)
{
  // string-based operators:
  case begins "Maria": // to catch Maria Carey
    break;
  case ends "Washington": // to catch George Washington
    break;
  case like "ph": // to catch Phil, Phillip, Sophie
    break;
  case between "Aaron" and "April": // to catch all names between
    break;

  // use non-static variables in case expression:
  case Dao.GetDefaultBabyName():
    break;

  // continuable cases without breaking
  case "John":
    bonus = 25;
  case "Peter":
    salary = 500;
    break;

  // jumps between cases
  case "Aleron":
    // do something
    break;
  case "Bella":
    // do something
    jump "Aleron";
    break;

}

และอื่น ๆ เช่นเดียวกับตัวเลขหรือชนิดอื่น ๆ (ที่สนับสนุนIComparable, IConvertible, ... )

นี่อาจทำให้โค้ดของฉันสั้นลงและอ่านง่ายขึ้น


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

0

มันเป็นคำถามที่สนุกอย่างที่ @Macneil พูด

โครงสร้างโปรดของฉันที่ผิดปกติการควบคุมซึ่งผม (ไออ่อนน้อมถ่อมตน) ค้นพบคือการดำเนินการที่แตกต่างกัน

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

ฉันมักจะใช้มันโดยแมโครใน C หรือ C ++ ใน C # ฉันต้องทำด้วยงบขยายมือ นั่นคือความเจ็บปวด แต่มันได้ผล

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


0

โครงสร้างการควบคุมแบบ "ดั้งเดิม" forนั้นเกี่ยวกับการควบคุมคนทำงานทำให้เขายอมจำนนต่ออุดมการณ์ที่เสียหายของชนชั้นนายทุนทุนนิยมผู้ปกครอง นั่นเป็นเหตุผลที่ฉันใช้โครงสร้างการควบคุมทางเลือกเช่นph0rแทน มันเหมือนforแต่หัวรุนแรงมากขึ้น: คุณจะไม่ph0rสวมชุดสูทและเน็คไททำให้มี BS ขององค์กร ph0rทำให้มันเป็นจริง

ต่อสู้กับพลัง!


0

ที่ง่ายforloop-

for(100)
{
    //Will run for 100 times
}


for(i)
{
    //Will run for i times while i must be a positive integer
}


for(i as a)
{
    //Will run for i times while i must be a positive integer
    //and a is the incremental loop variable starting from 0 and 
    //scoped within the loop
}


for(i as a=2)
{
    //Will run for i times while i must be a positive integer
    //and a is the incremental loop variable starting from 2 and 
    //scoped within the loop
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.