ภาษาตามจำนวน จำกัด ของอาร์กิวเมนต์ที่ส่งผ่านไปยังฟังก์ชัน


16

แนวคิดนี้ได้รับแรงบันดาลใจจากตัวดำเนินการข้อเท็จจริงเช่น +, -,%, เป็นต้นซึ่งสามารถมองเห็นได้ว่าเป็นฟังก์ชั่นที่ผ่านการโต้แย้งหนึ่งหรือสองครั้งและไม่มีผลข้างเคียง สมมติว่าฉันหรือคนอื่นเขียนภาษาที่หยุดไม่ให้มีการโต้แย้งมากกว่าสองข้อและยังใช้งานได้ผ่านการส่งคืนเท่านั้น:

ก) ภาษานั้นจะทำให้เข้าใจรหัสได้ง่ายขึ้นหรือไม่

b) การไหลของรหัสจะชัดเจนขึ้นหรือไม่ (บังคับให้ทำตามขั้นตอนมากขึ้นโดยที่การโต้ตอบ 'ซ่อน' อาจมีน้อยลง

c) ข้อ จำกัด จะทำให้ภาษามีขนาดใหญ่เกินไปสำหรับโปรแกรมที่ซับซ้อนมากขึ้น

d) (โบนัส) ความคิดเห็นอื่น ๆ เกี่ยวกับข้อดี / ข้อเสีย

บันทึก:

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


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

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

2
ไม่ใช่ว่ามีอะไรผิดปกติกับคำถาม 'เกิดอะไรขึ้น' (แม้ว่าบางครั้งพวกเขาก็ยากที่จะตอบตามที่ @MetaFight พูด) แต่ถ้าคุณผู้ที่คิดถึงสิ่งนั้นและใส่ใจพอที่จะถามคำถาม ได้รับประโยชน์จากนั้นฉันค่อนข้างมั่นใจว่าปฏิกิริยาแรกของฉันที่ว่า "อะไรนะ!

6
มีภาษาไม่กี่ภาษาที่อนุญาตให้มีการโต้แย้งเพียงครั้งเดียวต่อฟังก์ชั่น: ทุกอย่างขึ้นอยู่กับแคลคูลัสแลมบ์ดา result = f(a)(b)…(z)ผลที่ได้มักจะเป็นฟังก์ชั่นการโต้แย้งรายการเดียวหรือฟังก์ชั่นที่กลับมาฟังก์ชั่นที่ใช้เวลาโต้แย้งต่อไปจนกว่าจะมีข้อโต้แย้งทั้งหมดได้รับการประมวลผล: นี่เป็นกรณีในตระกูลภาษา ML เช่น Haskell แต่ยังมีแนวคิดในภาษาอื่นเช่น Lisp, JavaScript หรือ Perl
amon

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

คำตอบ:


40

Robert C. Martin ในหนังสือของเขา "Clean Code" แนะนำให้ใช้ฟังก์ชั่นอย่างมากด้วยพารามิเตอร์สูงสุด 0, 1 หรือ 2 ดังนั้นอย่างน้อยก็มีผู้เขียนหนังสือที่มีประสบการณ์คนหนึ่งที่คิดว่าโค้ดสะอาดขึ้นโดยใช้สไตล์นี้ แน่นอนว่าไม่ใช่อำนาจสูงสุดที่นี่และความคิดเห็นของเขาก็เป็นที่ถกเถียงกันอยู่)

ที่ Bob Martin ถูกต้อง IMHO คือ: ฟังก์ชั่นที่มีพารามิเตอร์ตั้งแต่ 3 ตัวขึ้นไปมักเป็นตัวบ่งชี้กลิ่นของรหัส ในหลายกรณีพารามิเตอร์อาจถูกจัดกลุ่มเข้าด้วยกันเพื่อสร้างประเภทข้อมูลที่รวมกันในกรณีอื่น ๆ ก็สามารถเป็นตัวบ่งชี้สำหรับฟังก์ชั่นการทำมากเกินไป

อย่างไรก็ตามฉันไม่คิดว่ามันเป็นความคิดที่ดีที่จะประดิษฐ์ภาษาใหม่สำหรับสิ่งนี้:

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

  • บางครั้งการรวมพารามิเตอร์กับประเภทใหม่ดูเหมือนจะไม่คุ้มค่ากับความยุ่งยากหรืออาจกลายเป็นการผสมผสานที่บริสุทธิ์ ดูตัวอย่างวิธีนี้File.Openจาก. Net framework ใช้พารามิเตอร์สี่ตัวและฉันค่อนข้างมั่นใจว่าผู้ออกแบบของ API นั้นทำสิ่งนี้โดยเจตนาเพราะพวกเขาคิดว่าจะเป็นวิธีที่ใช้งานได้จริงที่สุดในการมอบพารามิเตอร์ที่แตกต่างให้กับฟังก์ชัน

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


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

@PieterB: แน่นอนดูการแก้ไขของฉัน
Doc Brown

5
จิ๋วเล็ก nitpick ภาษา: "อาจบ่งชี้กลิ่นรหัส" ไม่ใช่กลิ่นรหัสโดยมีความหมายเพียงแค่เป็นตัวบ่งบอกว่าคุณควรจะพิจารณาบางสิ่งบางอย่างแม้ว่าคุณที่สุดไม่ได้เปลี่ยนรหัส? ดังนั้นกลิ่นรหัสจะไม่ถูก "ระบุ" หากลักษณะเฉพาะบ่งชี้ความเป็นไปได้ของปัญหามันเป็นกลิ่นรหัส ไม่มี?
jpmc26

6
@ jpmc26: จากมุมมองอื่นกลิ่นรหัสเป็นปัญหาที่เป็นไปได้ไม่ใช่ข้อบ่งชี้ของหนึ่ง ;-) ทุกอย่างขึ้นอยู่กับคำจำกัดความที่แน่นอนของรหัสกลิ่น (และเมื่อมันมีกลิ่นมันก็ไม่ดีใช่มั้ย ?)
hoffmale

3
@PieterB มีใครทำเช่นนี้จริง ๆ ไหม? ตอนนี้คุณต้องสร้างอินสแตนซ์ Person ใหม่ทุกครั้งที่คุณต้องการคำนวณ BMI ด้วยค่าสองค่า แน่นอนว่าหากแอปพลิเคชันของคุณใช้บุคคลที่จะเริ่มต้นด้วยและคุณพบว่าตัวเองมักทำอะไรบางอย่างเช่น f (person.length, person.height) คุณสามารถทำความสะอาดได้เล็กน้อย แต่การสร้างวัตถุใหม่โดยเฉพาะกับพารามิเตอร์กลุ่ม
Lawyerson

47

มีภาษามากมายที่ใช้วิธีนี้แล้วเช่น Haskell ใน Haskell ทุกฟังก์ชั่นใช้อาร์กิวเมนต์หนึ่งค่าและส่งกลับค่าเดียว

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

สิ่งนี้เรียกว่า Frege-Schönfinkeling, Schönfinkeling, Schönfinkel-Currying หรือ Currying หลังจาก Haskell Curry ผู้วิจัยเรื่องนี้อย่างกว้างขวางในปี 1950 โมเสสSchönfinkelผู้อธิบายไว้ในปี 1924

กล่าวอีกนัยหนึ่งการ จำกัด จำนวนอาร์กิวเมนต์มีผลกระทบเป็นศูนย์อย่างแน่นอน


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

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

3
@DocBrown ด้วยพลังที่เหมาะสมและการบรรทุกเกินพิกัดของผู้ใช้ฉันสามารถใช้ภาษาแกงและทำให้มันดูเหมือนภาษาที่ไม่ได้แปล ตัวอย่าง: f *(call_with: a,b,c,d,e) โอเวอร์โหลดcall_with :เพื่อเริ่มต้นลูกโซ่,ขยายลูกโซ่และ*บน LHS เพื่อเรียกใช้fโดยการส่งแต่ละเนื้อหาของลูกโซ่ทีละครั้ง ผู้ปฏิบัติงานระบบการบรรทุกเกินพิกัดที่อ่อนแออย่างเพียงพอเพียงแค่ทำให้ไวยากรณ์ยุ่งยาก แต่นั่นเป็นความผิดของผู้ประกอบการระบบการบรรทุกเกินพิกัดมากกว่าอะไร
Yakk

ที่จริงแล้วการแฮชของ Haskell ช่วยลดฟังก์ชั่นที่มี n อาร์กิวเมนต์ให้กับฟังก์ชันโดยมีหนึ่งอาร์กิวเมนต์ที่ส่งคืนฟังก์ชันอื่นที่มีอาร์กิวเมนต์ n - 1
Ryan Reich

2
@RyanReich คุณถูกต้องที่คุณสามารถเห็น "ผี" ของ "จำนวนอาร์กิวเมนต์" ของฟังก์ชัน Haskell ในลายเซ็นประเภท มันเป็นผีมากกว่าลายเซ็นจริงเพราะโดยทั่วไปคุณไม่มีทางรู้ไม่ว่าชนิดตัวแปรสุดท้ายในลายเซ็นยังประเภทฟังก์ชั่น ไม่ว่าจะด้วยวิธีใดก็ตามผีนี้จะไม่มีความจริงที่ว่าใน Haskell ฟังก์ชั่นทั้งหมดรับ 1 อาร์กิวเมนต์และส่งกลับค่าที่ไม่ใช่ฟังก์ชั่นหรือฟังก์ชั่นอื่นซึ่งยังใช้เวลา 1 อาร์กิวเมนต์ สิ่งนี้สร้างขึ้นในการเชื่อมโยงของ ->: a-> b-> c คือ a -> (b-> c) ดังนั้นคุณผิดที่นี่ส่วนใหญ่
เอียน

7

ฉันใช้เวลาในช่วงสองสามสัปดาห์ที่ผ่านมานี้เพื่อพยายามเรียนรู้ภาษาคอมพิวเตอร์ J ใน J เกือบทุกอย่างเป็นตัวดำเนินการดังนั้นคุณจะได้รับ "monads" (ฟังก์ชั่นที่มีเพียงหนึ่งอาร์กิวเมนต์เท่านั้น) และ "dyads" (ฟังก์ชั่นที่มีอาร์กิวเมนต์สองตัว) หากคุณต้องการอาร์กิวเมนต์เพิ่มเติมคุณต้องระบุในอาร์เรย์หรือระบุใน "กล่อง"

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


อาดังนั้นมันจึงช่วยให้อาร์เรย์สามารถโต้ตอบกับตัวเองได้

5

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

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

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

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


นี่คือคำตอบที่ดีที่สุด
Jared Smith

1

คุณจะต้องมีสองสิ่ง:

  • การปิด
  • ประเภทข้อมูลคอมโพสิต

ฉันจะเพิ่มเป็นตัวอย่างทางคณิตศาสตร์เพื่ออธิบายคำตอบที่เขียนโดยJörg W Mittag

พิจารณาฟังก์ชั่นเสีย

ฟังก์ชั่นเสียนมีสองพารามิเตอร์สำหรับรูปร่างของมันคือค่าเฉลี่ย (ตำแหน่งกึ่งกลางของเส้นโค้ง) และความแปรปรวน (เกี่ยวข้องกับความกว้างพัลส์ของเส้นโค้ง) นอกเหนือจากพารามิเตอร์สองตัวหนึ่งยังต้องระบุค่าของตัวแปรอิสระxเพื่อประเมิน

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

ในขั้นตอนที่สองเราสร้างประเภทข้อมูลคอมโพสิตที่รวมค่าเฉลี่ยและความแปรปรวนเป็นสิ่งเดียว

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

ในที่สุดเราประเมินการปิดที่สร้างขึ้นในขั้นตอนที่สามโดยส่งค่าของตัวแปรอิสระxให้กับมัน

โครงสร้างจึงเป็น:

  • ประเมิน (การคำนวณ)
    • ParameterizedGaussian (การปิด: สูตรพร้อมตัวแปรที่ถูกผูกไว้)
      • GaussianParameters (ประเภทข้อมูลคอมโพสิต)
        • ค่าเฉลี่ย (ค่า)
        • ความแปรปรวน (ค่า)
    • X (ค่าของตัวแปรอิสระ)

1
  1. ในเกือบทุกภาษาการเขียนโปรแกรมคุณสามารถส่งบางประเภทของรายการอาร์เรย์ tuple บันทึกหรือวัตถุเป็นอาร์กิวเมนต์เท่านั้น มีวัตถุประสงค์เพียงเพื่อเก็บสิ่งของอื่น ๆ แทนที่จะส่งไปยังฟังก์ชั่นทีละรายการ Java IDE บางตัวมีคุณสมบัติ " แยกพารามิเตอร์พารามิเตอร์ " เพื่อทำเช่นนั้น ภายใน Java ดำเนินการจำนวนตัวแปรของข้อโต้แย้งโดยการสร้างและผ่านอาร์เรย์

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

  3. ดูภาษาการเขียนโปรแกรมHaskellและML (ML นั้นง่ายกว่า) พวกเขาทั้งสองขึ้นอยู่กับแคลคูลัสแลมบ์ดาและแนวคิดมีเพียงหนึ่งพารามิเตอร์ต่อฟังก์ชั่น (ถ้าคุณเหล่เล็กน้อย)

  4. รายการที่ 2 ของ Josh Bloch คือ: "พิจารณาตัวสร้างเมื่อเผชิญกับพารามิเตอร์ตัวสร้างจำนวนมาก" คุณสามารถดูว่าสิ่งนี้ได้รับอย่างไร แต่ก็ยินดีที่ได้ทำงานกับ API ที่เขียนด้วยวิธีนี้

  5. บางภาษามีการตั้งชื่อพารามิเตอร์ซึ่งเป็นอีกวิธีหนึ่งในการทำให้ลายเซ็นของวิธีการขนาดใหญ่นำทางได้ง่ายกว่ามาก Kotlin ได้ตั้งชื่ออาร์กิวเมนต์เช่น

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