เหตุใดการเชื่อมโยงจึงไม่ใช่คุณลักษณะดั้งเดิมในภาษาส่วนใหญ่


11

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

แต่ IMHO ที่ใช้สิ่งนี้เป็นคุณสมบัติดั้งเดิมนั้นง่ายเหมือนการเปลี่ยนรหัสต่อไปนี้ -

int a,b,sum;
sum := a + b;
a = 10;
b = 20;
a++;

สำหรับสิ่งนี้-

int a,b,sum;
a = 10;
sum = a + b;
b = 20;
sum = a + b;
a++;
sum = a + b;

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

ดังนั้นทำไมจึงไม่รองรับในภาษาส่วนใหญ่ เป็นพิเศษในตระกูลภาษา C ใช่หรือไม่

ปรับปรุง:

จากความคิดเห็นที่แตกต่างกันฉันคิดว่าฉันควรนิยาม "การผูก" ที่เสนอนี้ให้แม่นยำยิ่งขึ้น -

  • นี่เป็นวิธีหนึ่งที่มีผลผูกพัน ผลรวมเท่านั้นที่ถูกผูกไว้กับ + b ไม่ใช่ในทางกลับกัน
  • ขอบเขตของการรวมเป็นแบบโลคัล
  • เมื่อสร้างการเชื่อมโยงแล้วจะไม่สามารถเปลี่ยนแปลงได้ ความหมายเมื่อผลรวมถูกผูกไว้กับ a + b ผลรวมจะเป็น a + b เสมอ

หวังว่าความคิดจะชัดเจนขึ้นในขณะนี้

อัปเดต 2:

ฉันแค่ต้องการฟีเจอร์ P #นี้ หวังว่ามันจะมีในอนาคต


14
อาจเป็นเพราะนักพัฒนาคอมไพเลอร์ที่พยายามเพิ่มคุณสมบัตินี้ลงใน C ได้ถูกตามล่าและยิง
Pete Wilson

ฉันกำลังพูดถึงการรวมทางเดียว (ขวาไปซ้าย) ไม่ใช่สองทาง การรวมจะมีผลกับตัวแปรเดียวเท่านั้น
Gulshan

2
สำหรับสิ่งที่คุ้มค่ามุมมองแบบโปรแกรมนี้กำลังสูงขึ้น: การเขียนโปรแกรมแบบตอบโต้ สิ่งที่คุณกำลังอธิบายก็เป็นตัวเป็นตนโดยโปรแกรมสเปรดชีตเช่น Excel ซึ่งเป็นหลักข้อมูลผูกพัน (หรือการเขียนโปรแกรมปฏิกิริยา) บนเตียรอยด์
Mike Rosenblum

11
อาจไม่ใช่คุณลักษณะของภาษาการเขียนโปรแกรม "ส่วนใหญ่" แต่เป็นคุณลักษณะของภาษาการเขียนโปรแกรมยอดนิยม : Excel
Jörg W Mittag

2
ขอขอบคุณต้นไม้แสดงออกซึ่งสามารถทำได้ใน C # ฉัน blogged เกี่ยวกับเรื่องนี้เมื่อวาน: happynomad121.blogspot.com/2013/01/…
HappyNomad

คำตอบ:


9

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

คุณต้องพิจารณาว่านี่ไม่ใช่สิ่งที่คุณต้องการ ดังนั้นคนจำนวนมากจะถูกกัดโดยการปิดสร้างขึ้นในลูปโดยเฉพาะเนื่องจากการปิดให้ตัวแปรที่ไม่สำเนาของความคุ้มค่าในบางจุดเช่นสร้างปิดสิบซึ่งผลตอบแทนfor (i = 0; i < 10; i++) { var f = function() { return i; }; /* store f */ } 9ดังนั้นคุณจะต้องสนับสนุนทั้งสองวิธี - ซึ่งหมายถึงสองเท่าของค่าใช้จ่ายใน "งบประมาณความซับซ้อน" และยังมีผู้ให้บริการรายอื่น อาจเป็นไปได้ที่ความไม่ลงรอยกันระหว่างรหัสที่ใช้สิ่งนี้และรหัสที่ไม่ได้ใช้สิ่งนี้ยกเว้นว่าระบบประเภทนั้นซับซ้อนพอ (ความซับซ้อนมากขึ้น!)

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

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


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

1
@Gulshan: (1) กระบวนทัศน์การเขียนโปรแกรมไม่มีคณิตศาสตร์ FP ใกล้เคียงกัน แต่ FP ค่อนข้างหายากและภาษา FP ที่ไม่บริสุทธิ์ที่มีตัวแปรที่ไม่แน่นอนไม่ได้ปฏิบัติกับตัวแปรเหล่านี้ราวกับว่าพวกเขามาจากคณิตศาสตร์เช่นกัน กระบวนทัศน์หนึ่งที่มีอยู่นี้คือการเขียนโปรแกรมแบบใช้ปฏิกิริยา แต่การเขียนโปรแกรมแบบโต้ตอบไม่เป็นที่รู้จักหรือใช้อย่างกว้างขวาง (ในภาษาการเขียนโปรแกรมดั้งเดิม) (2) ทุกอย่างมีความซับซ้อนและค่าใช้จ่าย สิ่งนี้มีค่าใช้จ่ายค่อนข้างสูงและมีค่าค่อนข้างน้อย IMHO ยกเว้นในบางโดเมนดังนั้นจึงไม่ใช่สิ่งแรกที่ฉันจะเพิ่มลงในภาษาของฉันเว้นแต่จะเป็นเป้าหมายเฉพาะโดเมนเหล่านี้

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

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

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

3

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


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

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

ฉันอยากจะแนะนำกฎที่ไม่สามารถเปลี่ยนนิพจน์การโยงได้เมื่อการโยงเสร็จสิ้น แม้การมอบหมายจะเป็นไปไม่ได้ มันจะเป็นเหมือนกึ่งคงที่เมื่อถูกผูกไว้กับการแสดงออก ซึ่งหมายความว่าเมื่อรวมเป็น a + b มันจะเป็น a + b ตลอดเวลาที่เหลือของโปรแกรม
Gulshan

3

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

IOW จาวาสคริปต์หลายบรรทัด ~ 3000 ที่ฉันเขียนไม่ได้ทำอะไรนอกจากค้นหาวัตถุ การเขียนโปรแกรมแบบโต้ตอบอาจทำทุกอย่างด้วยราคาที่ไม่แพง และลดจำนวนบรรทัดรหัสลงอย่างมาก

พวกคุณคิดอย่างไรเกี่ยวกับเรื่องนี้? ใช่ฉันสังเกตว่าตารางของฉันมีคุณสมบัติเหมือนสเปรดชีตมากมาย


3

ฉันคิดว่าสิ่งที่คุณกำลังอธิบายเรียกว่าสเปรดชีต:

A1=5
B1=A1+1
A1=6

... จากนั้นประเมินผลB1ตอบแทน 7

แก้ไข

บางครั้งภาษา C เรียกว่า "ชุดประกอบแบบพกพา" มันเป็นภาษาที่จำเป็นในขณะที่สเปรดชีต ฯลฯ เป็นภาษาที่เปิดเผย การพูดB1=A1+1และคาดหวังว่าB1จะประเมินใหม่เมื่อคุณเปลี่ยนA1เป็นการประกาศอย่างแน่นอน ภาษาที่มีการประกาศ (ซึ่งภาษาที่ใช้งานได้เป็นส่วนย่อย) โดยทั่วไปแล้วจะถือว่าเป็นภาษาระดับสูงกว่าเพราะพวกเขาอยู่ห่างจากวิธีการทำงานของฮาร์ดแวร์

ในบันทึกที่เกี่ยวข้องภาษาอัตโนมัติเช่นลอจิกลอจิกมักจะเป็นการประกาศ หากคุณเขียนรุ่งของตรรกะที่ระบุว่าoutput A = input B OR input Cมันจะประเมินคำสั่งนั้นใหม่อย่างต่อเนื่องและAสามารถเปลี่ยนแปลงได้ตลอดเวลาBหรือCเปลี่ยนแปลง ภาษาอัตโนมัติอื่น ๆ เช่น Function Block Diagram (ซึ่งคุณอาจคุ้นเคยถ้าคุณใช้ Simulink) ก็เป็นการประกาศและดำเนินการอย่างต่อเนื่อง

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

A = B || C;

... และเนื่องจากมันทำงานอยู่ตลอดเวลาจึงกลายเป็นสิ่งที่ประกาศได้ Aจะถูกประเมินอีกครั้งอย่างต่อเนื่อง


3

C, C ++, วัตถุประสงค์ -C:

บล็อกมีคุณสมบัติเข้าเล่มที่คุณต้องการ

ในตัวอย่างของคุณ:

ยอดรวม: = a + b;

คุณกำลังตั้งค่าsumการแสดงออกa + bในบริบทที่aและbเป็นตัวแปรที่มีอยู่ คุณสามารถทำสิ่งนั้นได้อย่างสมบูรณ์ด้วย "บล็อก" (การปิด aka หรือการแสดงออกแลมบ์ดา) ใน C, C ++ หรือ Objective-C พร้อมส่วนขยายของ Apple (pdf):

__block int a = 0, b = 0;           // declare a and b
int (^sum)(void);                   // declare sum
sum = ^(void){return a + b;};       // sum := a + b

ชุดนี้sumเป็นบล็อกที่ส่งคืนผลรวมของ a และ b ตัว__blockระบุคลาสหน่วยเก็บข้อมูลระบุว่าaและbอาจเปลี่ยนแปลง รับด้านบนเราสามารถเรียกใช้รหัสต่อไปนี้:

printf("a=%d\t b=%d\t sum=%d\n", a, b, sum());
a = 10;
printf("a=%d\t b=%d\t sum=%d\n", a, b, sum());
b = 32;
printf("a=%d\t b=%d\t sum=%d\n", a, b, sum());
a++;
printf("a=%d\t b=%d\t sum=%d\n", a, b, sum());

และรับผลลัพธ์:

a=0      b=0     sum=0
a=10     b=0     sum=10
a=10     b=32    sum=42
a=11     b=32    sum=43

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


2

C ++

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

#include <iostream>

template <class R, class A, class B>
class Binding {
public:
    typedef R (*BinOp)(A, B);
    Binding (A &x, B &y, BinOp op)
        : op(op)
        , rx(x)
        , ry(y)
        , useCache(false)
    {}
    R value () const {
        if (useCache && x == rx && y == ry) {
            return cache;
        }
        x = rx;
        y = ry;
        cache = op(x, y);
        useCache = true;
        return cache;
    }
    operator R () const {
        return value();
    }
private:
    BinOp op;
    A &rx;
    B &ry;
    mutable A x;
    mutable B y;
    mutable R cache;
    mutable bool useCache;
};

int add (int x, int y) {
    return x + y;
}

int main () {
    int x = 1;
    int y = 2;
    Binding<int, int, int> z(x, y, add);
    x += 55;
    y *= x;
    std::cout << (int)z;
    return 0;
}

แม้ว่ามันจะไม่ตอบคำถาม แต่ฉันชอบไอเดียที่คุณนำเสนอ จะมีเวอร์ชั่นที่กว้างกว่านี้อีกไหม?
Gulshan

@Gulshan: อัปเดต
Thomas Eding
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.