Function

ถ้าลองใช้ :t ตรวจชนิดของฟังก์ชันดูบ้าง จะเห็นแบบนี้

    ghci> :t fromIntegral
    fromIntegral :: (Integral a, Num b) => a -> b

ส่วนที่บอก type จะอยู่หลังเครื่องหมาย => เช่นเคย โดยฝั่งซ้ายของ -> จะเป็นตัวแปรที่รับเข้ามาในฟังก์ชัน ส่วนฝั่งขวาคือผลลัพท์จากฟังก์ชัน นั่นหมายความว่าฟังก์ชัน fromIntegral รับตัวแปรใน type class Integral แล้วได้ผลลัพท์เป็น type class Num

การเขียนฟังก์ชันนั้น เช่นเดียวกับการประกาศค่าคงที่ คือใช้ let พร้อมชื่อฟังก์ชันและตัวแปร เช่น

    ghci> let half x = x / 2

ทีนี้ลองดูฟังก์ชันของ 2 ตัวแปรกันบ้าง

    ghci> :t mod
    mod :: Integral a => a -> a -> a

สิ่งที่แตกต่างไปจากภาษา imperative และถือได้ว่าเป็นจุดเด่นของภาษาแบบ functional เลยคือ แทนที่ type ของฟังก์ชัน 2 ตัวแปรจะใช้ช่องว่างคั่นตัวแปร (type น่าจะอยู่ในรูป a a -> a) แต่ระหว่างตัวแปรกลับใช้สัญลักษณ์ -> เช่นเดียวกับการบอกผลลัพท์ที่ได้จากฟังก์ชัน

เราอาจลองแบ่งกลุ่มเพื่อความกระจ่างใน type ว่ามันคือ a -> (a -> a) ซึ่งหมายความว่า ฟังก์ชันนี้เป็นฟังก์ชันที่รับตัวแปร 1 ตัว แล้วให้ผลลัพท์เป็นฟังก์ชันที่รับตัวแปร 1 ตัวแล้วคืนค่าออกมาก็ย่อมได้

นั่นหมายความว่า ฟังก์ชัน 2 ตัวแปร แท้จริงแล้วคือฟังก์ชัน 1 ตัวแปร 2 ชั้น เราจึงสามารถเรียกฟังก์ชันแบบนี้

    ghci> (mod 123456789) 1009
    594

ได้เช่นกัน นี่เป็นเหตุผลว่าทำไม Haskell ถึงไม่ใช้วงเล็บล้อมรอบตัวแปร เราเรียกเทคนิคการทำให้ฟังก์ชันหลายตัวแปรกลายร่างเป็นฟังก์ชันตัวแปรเดียวซ้อนๆ กันเช่นนี้ว่า currying และเรียกฟังก์ชันที่รับตัวแปรเข้าไปแล้วบ้างแต่ยังไม่ครบว่า partial application ครับ


อนึ่ง เราสามารถเขียนการหารเก็บเศษข้างบนเป็นแบบนี้ 123456789 `mod` 1009 และถ้าเราเอาวงเล็บล้อมรอบ `mod` 1009 ด้านหลัง มันจะกลายเป็นฟังก์ชันที่รับตัวแปรไปแล้ว 1 ตัว และต้องการอีก 1 ที่ต้องทำต่อคือย้ายมันไปไว้ข้างหน้าเท่านั้นเอง

    ghci> (`mod` 1009) 123456789
    594

ซึ่งสามารถจับมาประกาศเป็นฟังก์ชันได้ว่า

    ghci> let modWithPrime x = (`mod` 1009) x

หรือยิ่งไปกว่านั้น

    ghci> let modWithPrime = (`mod` 1009)
    ghci> modWithPrime 123456789
    594

กลับไปดูฟังก์ชัน half ที่เขียนไว้ตอนต้นอีกที เราลองเขียนมันใหม่เป็น

    ghci> let half = (/2)
    ghci> half 50
    25.0

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

    ghci> :t (/)
    (/) :: Fractional a => a -> a -> a

นั่นหมายความว่า operator เหล่านั้นก็ถือเป็นฟังก์ชันเช่นเดียวกันนั่นเอง

Nattawut Phetmak

Jack of all Trades

blog comments powered by Disqus