นี่เป็นแบบฝึกหัดที่ดีในการใช้ภาษาโปรแกรมที่คุณตั้งใจจะเรียนรู้ แต่มีเพียงเล็กน้อยเท่านั้น สิ่งนี้เกี่ยวข้องกับการทำงานกับวัตถุการใช้หรือการจำลองการปิดและการยืดระบบชนิด
งานของคุณคือการเขียนโค้ดเพื่อจัดการรายการที่ขี้เกียจจากนั้นใช้เพื่อใช้อัลกอริทึมนี้ในการสร้างหมายเลข Fibonacci:
ตัวอย่างรหัสอยู่ใน Haskell
let fibs = 0 : 1 : zipWith (+) fibs (tail fibs)
in take 40 fibs
ผล:
[0,1,1,2,3,5,8,13,21,34,55,89,144,233,377,610,987,1597,2584,4181,6765,10946,17711,28657,46368,75025,121393,196418,317811,514229,832040,1346269,2178309,3524578,5702887,9227465,14930352,24157817,39088169,63245986]
การใช้งานรายการที่ขี้เกียจของคุณควรเป็นไปตามหลักเกณฑ์เหล่านี้:
- List List เป็นหนึ่งในสามสิ่ง:
- ไม่มี - รายการว่างเปล่า
[]
- ข้อด้อย - รายการเดียวจับคู่กับรายชื่อของรายการที่เหลือ:
1 : [2,3,4,5]
(:
เป็นผู้ประกอบการ cons ใน Haskell) - Thunk - การคำนวณที่เลื่อนออกไปซึ่งสร้างโหนดรายการเมื่อต้องการ
- ไม่มี - รายการว่างเปล่า
- สนับสนุนการดำเนินการดังต่อไปนี้:
- ไม่มี - สร้างรายการที่ว่างเปล่า
- cons - สร้างเซลล์ข้อเสีย
- thunk - สร้าง Thunk ให้ฟังก์ชั่นที่ไม่มีการขัดแย้งและส่งกลับศูนย์หรือข้อด้อย
- แรง - รับโหนดรายการ:
- หากเป็น Nil หรือ Cons ให้ส่งคืน
- ถ้าเป็น Thunk ให้เรียกใช้ฟังก์ชันเพื่อรับ Nil หรือ Cons แทนที่ thunk ด้วย Nil หรือ Cons นั้นและส่งคืน
หมายเหตุ:การเปลี่ยน thunk ที่มีค่าบังคับมันเป็นส่วนสำคัญของคำนิยามของ "ขี้เกียจ" หากข้ามขั้นตอนนี้อัลกอริทึม Fibonacci ด้านบนจะช้าเกินไป
- empty - ดูว่าโหนด List เป็น Nil หรือไม่ (หลังจากบังคับใช้)
- หัว (aka "รถยนต์") - รับไอเท็มแรกของรายการ (หรือโยนให้พอดีถ้าไม่มี)
- tail (aka "cdr") - รับองค์ประกอบหลังส่วนหัวของรายการ (หรือโยนให้พอดีถ้าไม่มี)
- zipWith - รับฟังก์ชั่นไบนารี (เช่น
(+)
) และสองรายการ (อาจไม่มีที่สิ้นสุด) ใช้ฟังก์ชันกับรายการที่สอดคล้องกันของรายการ ตัวอย่าง:
zipWith (+) [1,2,3] [1,1,10] == [2,3,13]
- รับ - รับหมายเลข N และรายการ (อาจไม่มีที่สิ้นสุด) คว้ารายการ N แรกของรายการ
- พิมพ์ - พิมพ์รายการทั้งหมดในรายการ สิ่งนี้จะทำงานได้เพิ่มขึ้นเมื่อมีรายการยาวหรือไม่สิ้นสุด
fibs
ใช้ตัวเองในคำนิยามของตัวเอง การตั้งค่าการเรียกซ้ำแบบขี้เกียจนั้นค่อนข้างยุ่งยาก คุณจะต้องทำสิ่งนี้:- จัดสรร thunk
fibs
สำหรับ ปล่อยให้มันอยู่ในสถานะหลอกตาสำหรับตอนนี้ - กำหนดฟังก์ชั่น thunk
fibs
ซึ่งขึ้นอยู่กับการอ้างอิงถึง - อัพเดต thunk ด้วยฟังก์ชัน
คุณอาจต้องการซ่อนการวางท่อประปานี้โดยการกำหนดฟังก์ชั่น
fix
ที่เรียกฟังก์ชั่นList-return พร้อมกับคืนค่าของมันเอง ลองงีบหลับสั้น ๆ เพื่อให้ความคิดนี้สามารถตั้งค่าได้- จัดสรร thunk
Polymorphism (ความสามารถในการทำงานกับรายการประเภทใดก็ได้) ไม่จำเป็นต้องใช้ แต่ดูว่าคุณสามารถหาวิธีที่จะใช้สำนวนที่เป็นสำนวนในภาษาของคุณได้ไหม
- ไม่ต้องกังวลกับการจัดการหน่วยความจำ แม้แต่ภาษาที่มีการรวบรวมขยะมีแนวโน้มที่จะนำพาวัตถุไปด้วยคุณจะไม่ใช้อีก (เช่นใน call stack) ดังนั้นอย่าแปลกใจถ้าโปรแกรมของคุณมีหน่วยความจำรั่วขณะสำรวจรายการที่ไม่สิ้นสุด
รู้สึกอิสระที่จะเบี่ยงเบนเล็กน้อยจากหลักเกณฑ์เหล่านี้เพื่อรองรับรายละเอียดของภาษาของคุณหรือเพื่อค้นหาวิธีอื่นในการทำรายการที่ขี้เกียจ
กฎ:
- เลือกภาษาที่คุณไม่รู้ ฉันไม่สามารถ "ต้องการ" สิ่งนี้ได้ดังนั้นแท็ก "ระบบเกียรติ" อย่างไรก็ตามผู้ลงคะแนนสามารถตรวจสอบประวัติของคุณเพื่อดูว่าคุณโพสต์ภาษาใดบ้าง
อย่าใช้การสนับสนุนรายการสันหลังยาวในภาษาของคุณเพื่อทำทุกอย่าง โพสต์สิ่งที่น่าสนใจหรืออย่างน้อยน่าสนใจ
Haskell สวยมาก นั่นคือเว้นแต่คุณจะทำสิ่งนี้:
data List a = IORef (ListNode a) data ListNode a = Nil | Cons !a !(List a) | Thunk !(IO (ListNode a))
หมายเหตุ: การประเมินที่ไม่เข้มงวดของ Haskell ไม่ได้ จำกัด อยู่ แต่การใช้งานรายการที่ขี้เกียจของคุณไม่ควรได้รับความสามารถโดยตรงจากที่นั่น ในความเป็นจริงมันน่าสนใจที่จะเห็นโซลูชันที่มีประสิทธิภาพและใช้งานได้อย่างหมดจดโดยไม่ต้องมีความขี้เกียจ
งูหลาม:
- อย่าใช้ itertools
- เครื่องกำเนิดไฟฟ้านั้นใช้ได้ แต่คุณใช้พวกมันคุณจะต้องหาวิธีในการบันทึกค่าบังคับ
zipWith (+) [1,2,3,4,5] [0,0,0] == [1,2,3]
. อย่างไรก็ตามสิ่งนี้ไม่สำคัญสำหรับอัลกอริทึม Fibonacci ด้านบนเนื่องจากอาร์กิวเมนต์ทั้งสองของ zipWith เป็นรายการที่ไม่สิ้นสุด
fibs
อย่างถูกต้องเนื่องจากขึ้นอยู่กับตัวเอง ฉันอัปเดตคำถามเพื่ออธิบายรายละเอียดเกี่ยวกับการเรียกซ้ำที่ขี้เกียจ FUZxxlคิดออกโดยเขา / เธอ / ตัวเอง
zipWith
สองรายการที่มีความยาวต่างกัน?