December 13, 2012

Haskell: ทำงานกับ List ที่ยาวเป็นอนันต์

การประกาศ List นอกจากจะทำได้ตามวิธีปรกติแล้ว Haskell ยังทำท่านี้ได้อีกด้วย


ค่าที่เพิ่มจะเพิ่มขึ้นครั้งละ 1 หน่วย (ถ้าตัวเลขก็คือ +1 ถ้าเป็นตัวอักษรก็คือตัวอักษรถัดไป) เราสามารถแก้ไขค่าที่จะเพิ่มขึ้นได้โดยบอกสมาชิกตัวถัดไปใน List นี้แทน


สมาชิกตัวสุดท้ายที่บอกขอบเขตบนนั้น อาจอยู่หรือไม่อยู่ใน List ที่สร้างเสร็จก็ได้ แต่จะไม่มีสมาชิกที่มีค่าใหญ่กว่านี้ครับ

ส่วนการประกาศค่าแบบลดลงนั้น ไม่สามารถบอกแค่ [10..1] ได้ ต้องบอกสมาชิกตัวถัดมาด้วย


หมายเหตุว่าให้ระวังการประกาศ List แบบนี้กับเลขทศนิยม เพราะ bug ของตัว Haskell เองทำให้อาจมีสมาชิกที่ใหญ่กว่าขอบเขตบนโผล่มาได้ครับ

อนึ่ง เราสามารถละส่วนขอบเขนบนได้ โดย Haskell จะเอาขอบเขตบนของ type นั้นมาเติมให้เอง เช่น


ปล่อยไว้ซักพัก จะเห็นว่า List ที่สร้างขึ้นนี้วิ่งไปจบที่ตัวอักษรซักตัวเอง และถ้าสงสัยว่าขอบเขตบนนั้นคืออะไร ก็สามารถหาได้โดย


แต่สำหรับข้อมูลบาง type ที่ไม่มีขอบเขตบน (เช่น Integer) เมื่อสั่ง [1..] ตัวเลขจะวิ่งขี้นไปเรื่อยๆ ไม่มีที่สิ้นสุดครับ (เป็น List ที่ยาวเป็นอนันต์)



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

ฟังก์ชันที่ใช้เพื่อขอสมาชิกเพียงไม่กี่ตัวแรกของ List จากทางด้านหน้าคือ take


ส่วน drop นั้นจะใช้เพื่อทิ้งสมาชิกตัวหน้าออกไป


(drop เพียงอย่างเดียวนั้นไม่ค่อยมีประโยชน์กับ List ที่ยาวเป็นอนันต์ครับ)

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


ย้ำอีกทีว่าฟังก์ชันพวกนี้จะเริ่มทำงานจากด้านหัว และคืนค่าทันทีเมื่อเงื่อนไขครบ เห็นได้จาก dropWhile (/=3) ที่ทิ้งเลข [1,2] เฉพาะทางด้านหัวเท่านั้น



นอกจากจะใช้การประกาศ List ตามด้านบนเพื่อสร้าง List ที่ยาวอนันต์ได้แล้ว ยังสามารถสร้าง List ที่ยาวเป็นอนันต์โดยใช้ฟังก์ชันเหล่านี้

cycle รับตัวแปรเป็น List ที่จะเอามาทำซ้ำเรื่อยๆ


ส่วน repeat จะรับตัวแปรคือสมาชิกตัวเดียวของ List ที่จะเอาไปทำซ้ำๆ แต่ถ้ารู้ขนาดที่แน่นอนอยู่แล้ว สามารถใช้ฟังก์ชัน replicate แทนได้

No comments:

Post a Comment