ทำไม 'zip' ถึงไม่สนใจหางที่ห้อยอยู่ของคอลเลกชัน?


12

C # , Scala, Haskell, Lisp และPythonมีzipพฤติกรรมเหมือนกัน: หากคอลเล็กชันหนึ่งยาวกว่าหางจะถูกละเว้นอย่างเงียบ ๆ

อาจเป็นข้อยกเว้นได้เช่นกัน แต่ฉันไม่เคยได้ยินภาษาใด ๆ ที่ใช้วิธีการนี้

ปริศนานี้ฉัน ไม่มีใครรู้เหตุผลว่าทำไมzipถูกออกแบบมาอย่างนั้น? ฉันเดาภาษาใหม่เพราะมันเป็นภาษาอื่นทำแบบนี้ แต่อะไรคือเหตุผลหลัก

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

อัปเดต : ถ้าฉันถูกถามว่าจะทำอย่างไรฉันจะพูดว่า - โยนข้อยกเว้นคล้าย ๆ กับการจัดทำดัชนีอาเรย์ (แม้ว่าภาษา "โบราณ" ทุกชนิดมีเวทมนตร์ทุกชนิดวิธีจัดการกับดัชนีขอบเขต UB ขยายอาร์เรย์ ฯลฯ )


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

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

@KilianFoth ได้รับการยกเว้น
greenoldman

@Dupuplicator เป็นคนดี ด้วยการลดลงของหางเงียบคุณสามารถแสดงzipWithIndexธรรมชาติกำเนิดตัวเลข ตอนนี้เพียงชิ้นเดียวที่ขาดหายไปของข้อมูล - สิ่งที่มันมีเหตุผลหรือไม่ :-) (btw. กรุณาโพสต์ใหม่ความคิดเห็นของคุณเป็นคำตอบขอขอบคุณ)
greenoldman

1
Python มี itertools.izip_longest ซึ่งทำให้การป้อนอัตโนมัติเสร็จสิ้นอย่างมีประสิทธิภาพด้วย Nones ฉันเลือก zip บ่อยครั้งเมื่อใช้ zip จริง ๆ ฉันไม่สามารถจำเหตุผลที่อยู่เบื้องหลังตัวเลือกใด ๆ ได้อีกต่อไป Python มีการแจกแจง () สำหรับกรณีของ @ greenoldman แล้วซึ่งฉันใช้บ่อย
StarWeaver

คำตอบ:


11

เป็นเกือบทุกอย่างที่คุณต้องการและเมื่อไม่มีคุณสามารถทำเองได้

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

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


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

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

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

3
+1 นี่ยังเป็นคำตอบที่ยอดเยี่ยม "โปรแกรมเมอร์ที่ใช้งานได้ชอบโครงสร้างที่ไม่สามารถล้มเหลวได้ด้วยการออกแบบ" ดังนั้นสิ่งนี้จึงกล่าวอย่างชัดเจนว่าอะไรคือแรงจูงใจที่ใหญ่ที่สุดที่อยู่เบื้องหลังการตัดสินใจออกแบบส่วนใหญ่ โปรแกรมเมอร์ที่มีความจำเป็นมีกฎที่บอกว่า "บอกไม่ต้องถาม", FP นำสิ่งนี้ไปที่ระดับ Nth โดยมุ่งเน้นที่การให้คำแนะนำอย่างต่อเนื่องโดยไม่ต้องตรวจสอบผลลัพธ์จนกว่าจะถึงช่วงเวลาสุดท้ายดังนั้นเราจึงพยายามทำให้ขั้นตอนกลางไม่สามารถล้มเหลวได้เพราะ Composability เป็นราชา พูดได้เป็นอย่างดี.
Jimmy Hoffa

12

เนื่องจากไม่มีวิธีที่ชัดเจนในการทำให้หางสมบูรณ์ ตัวเลือกใด ๆ เกี่ยวกับวิธีการทำมันจะส่งผลให้หางไม่ชัดเจน

เคล็ดลับคือการยืดรายการที่สั้นที่สุดของคุณให้ตรงกับความยาวของรายการที่ยาวที่สุดกับค่าที่คุณคาดไว้

หากซิปทำอย่างนั้นกับคุณคุณไม่สามารถรู้ได้ว่าค่าอะไรที่เติมเข้ามาโดยสัญชาตญาณ มันวนรอบรายการหรือไม่? มันทำซ้ำค่า mempty หรือไม่? ค่า mempty สำหรับประเภทของคุณคืออะไร

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


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

แม้ว่าจะจำได้ว่าเหตุผลนี้และฟังก์ชั่นสไตล์ FP ทั่วไปอื่น ๆ นั้นเป็นเรื่องธรรมดา แต่เป็นเพราะมันง่ายและทั่วไปเพื่อให้คุณสามารถปรับแต่งโค้ดเพื่อใช้งานและรับพฤติกรรมที่คุณต้องการ ตัวอย่างเช่นใน C # คุณสามารถทำได้

IEnumerable<Tuple<T, U>> ZipDefaults(IEnumerable<T> first, IEnumerable<U> second)
{
    return first.Count() < second.Count()
        ? first.Concat(Enumerable.Repeat(default(T), second.Count() - first.Count())).Zip(second)
        : first.Zip(second.Concat(Enumerable.Repeat(default(U), first.Count() - second.count())))
}

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


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

2
zipสามารถกรอกข้อมูลเป็นโมฆะซึ่งมักจะเป็นทางออกที่ง่าย zip :: [a] -> [b] -> [(Maybe a, Maybe b)]พิจารณาประเภท ได้รับแล้วประเภทผลลัพธ์จะเป็นบิต ^ H ^ H ค่อนข้างทำไม่ได้ แต่จะอนุญาตให้ใช้พฤติกรรมอื่น ๆ ได้อย่างง่ายดาย (ทางลัดยกเว้น) ด้านบนของมัน
amon

1
@ มอน: มันไม่ง่ายเลย แต่มันก็โง่ มันจะต้องมีการตรวจสอบเป็นโมฆะทุกอาร์กิวเมนต์
DeadMG

4
@ ไม่ทุกประเภทมีโมฆะนั่นคือสิ่งที่ฉันหมายถึงmemptyวัตถุมีโมฆะเพื่อเติมเต็มพื้นที่ แต่คุณต้องการให้มันเกิดขึ้นกับสิ่งนั้นสำหรับ int และประเภทอื่น ๆ ด้วยใช่ไหม แน่นอนว่า C # มีdefault(T)แต่ไม่ทุกภาษาและแม้แต่ C # ก็เป็นพฤติกรรมที่ชัดเจนจริงๆ ผมไม่คิดอย่างนั้น
จิมมี่ฮอฟฟา

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