Nattawut Phetmak
Jack of all Trades
ระบบชนิดตัวแปรของ Haskell จะแตกต่างจากภาษาอื่นๆ ตรงที่แบ่งออกได้เป็น 2 ส่วน คือ
อาจมองได้ง่ายๆ อีกอย่างว่า type คือวิธี implement ข้อมูล ส่วน type class จะเป็นตัวกำหนดความสามารถของ type นั้นๆ ครับ
ซึ่งตัวเลขใน Haskell สามารถจัดแบ่งคร่าวๆ ได้ดังนี้
Num
    Integral
        Int จำนวนเต็มตามขนาด word ของคอมพิวเตอร์Integer จำนวนเต็มในอุดมคติ ไม่มีขอบเขตบน/ล่างFloating, Fractional
        
      และเราสามารถตรวจสอบ type ได้โดยใช้ command :t (หรือเต็มๆ คือ :type) แล้วตามด้วยตัวแปร เช่น
    ghci> :t 42
    42 :: Num a => a
    ghci> :t 1.0
    1.0 :: Fractional a => a
    ghci> :t 42 + 1.0
    42 + 1.0 :: Fractional a => a
type class พร้อมตัวแปรที่ใช้แสดงแทนนั้น จะถูกบอกไว้ก่อนเครื่องหมาย => ส่วนอีกด้านจะบอก type ของตัวแปร ซึ่งในกรณีที่เราไม่ได้เจาะจง type ลงไปเช่นนี้ Haskell จะจัดมันไว้ใน type class ที่ใหญ่ที่สุดไว้ก่อน เพื่อที่ว่าถ้าดำเนินการกับ type class ที่เป็นลูกหลานของมันจะยังให้ผลลัพท์ที่ถูกต้อง
ส่วนการประกาศ type แบบเจาะจงก็ทำได้โดยใส่ 2 colon แล้วตามด้วย type ไว้ข้างหลังตัวแปรนั้น
    ghci> let answer = 42 :: Float
    ghci> :t answer
    answer :: Float
จะเห็นว่าคราวนี้ไม่มีการบอก type class กับ => แล้ว เพราะเรารู้ type ที่แน่นอนของมันนั่นเอง
อย่างที่บอกไว้แต่ต้น การดำเนินการข้าม type หรือ type class ที่ไม่เกี่ยวข้องกันนั้น ไม่สามารถทำได้ใน Haskell เช่น error ในตัวอย่างนี้
    ghci> (1 :: Int) + (1 :: Integer)
    <interactive>:2:15:
        Couldn't match expected type `Int' with actual type `Integer'
        In the second argument of `(+)', namely `(1 :: Integer)'
        In the expression: (1 :: Int) + (1 :: Integer)
        In an equation for `it': it = (1 :: Int) + (1 :: Integer)
เลขทั้งสองตัวนั้นก็ต่างอยู่ใน type class Integral เหมือนกัน แต่เมื่อถูกกำหนดโดย type ต่างกัน จะทำให้ไม่สามารถนำมาบวกกันได้
ทางออกคือ
fromIntegral เพื่อเปลี่ยน type class กลับไปเป็น Num ก่อนเอาไปคำนวณต่อtruncate (ปัดทิ้ง), floor (ปัดลง), ceiling (ปัดขึ้น), round (ปัดครึ่ง) เพื่อเปลี่ยน type class เป็น Integral ได้