December 3, 2012

Haskell: ชนิดของฟังก์ชัน

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


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

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




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


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

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

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


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



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


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


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




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


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



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

December 2, 2012

PHP: ระบบสมาชิก - สมัครสมาชิก

งานการทำงานด้านเว็บด้วยภาษาฝั่งเซิฟเวอร์ มักจะมีความเกี่ยวข้องกับระบบฐานข้อมูลอยู่เสมอ ๆ หนึ่งในนั้นคือ ระบบสมาชิก เว็บหลายเว็บในปัจจุบัน มีการเชื่อมต่อระบบสมาชิกเข้ากับ social network ต่าง ๆ เพื่อความสะดวกให้กับผู้ใช้ แต่ผู้ใช้บางคนอาจจะไม่ต้องการผูกบัญชีของ social network เข้ากับบางเว็บ ด้วยเหตุผลต่าง ๆ นานา ระบบสมาชิกจึงยังจำเป็นอยู่

ตอนแรกขอพูดถึงการสมัครสมาชิกก่อน แล้วตอนต่อไปจะว่ากันเรื่องการ log in และ log out เพราะถ้ายังไม่สมัครสมาชิกก่อน ก็ log in ไม่ได้...

ในระบบสมาชิก สิ่งที่จำเป็นจริง ๆ มีอยู่ 2 อันคือ ชื่อผู้ใช้ และ รหัสผ่าน แต่ควรจะมี อีเมล เพื่อใช้ในการติดต่อกับสมาชิกไว้ด้วย

จะขอข้ามไม่พูดถึงเรื่องการสร้างฐานข้อมูล และตาราง แต่จะบอกแค่ชื่อ และโครงสร้างของตาราง นอกจากนั้น ใช้ความรู้เรื่อง PHP และ PDO เขียนสคริปท์ PHP กันเอาเอง หรือไม่ก็ใช้เครื่องมือจัดการฐานข้อมูลอย่าง phpMyAdmin (MySQL), phpPgAdmin (PostgreSQL) หรือตัวอื่น ๆ ตามแต่ละชนิดฐานข้อมูลกันตามสะดวก
เมื่อฐานข้อมูลพร้อมแล้ว ก็สร้างแบบฟอร์มสำหรับสมัครสมาชิกขึ้นมาก่อน เมื่อมีคนมาสมัครสมาชิก ข้อมูลจะถูกส่งมายัง regis.php ก็ต้องตรวจสอบค่าให้ถูกต้องเรียบร้อยก่อนว่าผู้ใช้กรอกข้อมูลครบถ้วนสมบูรณ์ดี หากผิดพลาดก็แจ้งเตือนกลับไป เมื่อตรวจสอบข้อมูลเรียบร้อยแล้ว หากไม่มีอะไรผิดพลาดก็เชื่อมต่อกับฐานข้อมูล และตรวจสอบว่ามีใครใช้ชื่อนี้ไปก่อนหรือยัง เพราะชื่อบัญชีห้ามซ้ำกัน

Haskell: ชนิดของตัวเลข

ระบบชนิดตัวแปรของ Haskell จะแตกต่างจากภาษาอื่นๆ ตรงที่แบ่งออกได้เป็น 2 ส่วน คือ
  1. type class ลำดับชั้นของตัวแปรที่บ่งบอกความสัมพันธ์กับฟังก์ชันต่างๆ
  2. type ชนิดของตัวแปร โดยตัวแปรชนิดนึงสามารถมีได้หลาย class
อาจมองได้ง่ายๆ อีกอย่างว่า type คือวิธี implement ข้อมูล ส่วน type class จะเป็นตัวกำหนดความสามารถของ type นั้นๆ ครับ

ซึ่งตัวเลขใน Haskell สามารถจัดแบ่งคร่าวๆ ได้ดังนี้
  • ตัวเลข class: Num
    • จำนวนเต็ม class: Integral
    • ทศนิยม class: Floating, Fractional
      • type: Float ทศนิยมแบบ single ความละเอียด 9 หลัก
      • type: Double ทศนิยมแบบ double ความละเอียด 18 หลัก



และเราสามารถตรวจสอบ type ได้โดยใช้ command :t (หรือเต็มๆ คือ :type) แล้วตามด้วยตัวแปร เช่น


type class พร้อมตัวแปรที่ใช้แสดงแทนนั้น จะถูกบอกไว้ก่อนเครื่องหมาย => ส่วนอีกด้านจะบอก type ของตัวแปร ซึ่งในกรณีที่เราไม่ได้เจาะจง type ลงไปเช่นนี้ Haskell จะจัดมันไว้ใน type class ที่ใหญ่ที่สุดไว้ก่อน เพื่อที่ว่าถ้าดำเนินการกับ type class ที่เป็นลูกหลานของมันจะยังให้ผลลัพท์ที่ถูกต้อง

ส่วนการประกาศ type แบบเจาะจงก็ทำได้โดยใส่ 2 colon แล้วตามด้วย type ไว้ข้างหลังตัวแปรนั้น


จะเห็นว่าคราวนี้ไม่มีการบอก type class กับ => แล้ว เพราะเรารู้ type ที่แน่นอนของมันนั่นเอง

อย่างที่บอกไว้แต่ต้น การดำเนินการข้าม type หรือ type class ที่ไม่เกี่ยวข้องกันนั้น ไม่สามารถทำได้ใน Haskell เช่น error ในตัวอย่างนี้


เลขทั้งสองตัวนั้นก็ต่างอยู่ใน type class Integral เหมือนกัน แต่เมื่อถูกกำหนดโดย type ต่างกัน จะทำให้ไม่สามารถนำมาบวกกันได้

ทางออกคือ
  • จำนวนเต็มสามารถใช้ฟังก์ชัน fromIntegral เพื่อเปลี่ยน type class กลับไปเป็น Num ก่อนเอาไปคำนวณต่อ
  • ทศนิยมใช้ฟังก์ชัน truncate (ปัดทิ้ง), floor (ปัดลง), ceiling (ปัดขึ้น), round (ปัดครึ่ง) เพื่อเปลี่ยน type class เป็น Integral ได้

December 1, 2012

Haskell: ใช้เป็นเครื่องคิดเลข

ตัวเลขใน Haskell ก็เหมือนภาษาอื่น ที่แบ่งออกหลักๆ เป็นจำนวนเต็มกับทศนิยม

โดยการประกาศทศนิยม จะมีข้อบังคับว่า หน้าและหลังจุดทศนิยมต้องมีตัวเลขเสมอ (แม้จะเป็น 0 ก็ตาม)



การดำเนินการบวกลบคูณหาร ก็ใช้ operator +, -, *, / เช่นเดียวกับภาษาอื่นๆ

สังเกตว่าการหารจะให้ผลลัพท์เป็นทศนิยมเสมอ ส่วนการหารแบบไม่เก็บเศษ (ให้ผลลัพท์เป็นจำนวนเต็ม) จะใช้ฟังก์ชัน div แทน

จะเห็นว่า การเรียกฟังก์ชั่นใน Haskell ไม่ใช้วงเล็บล้อมรอบตัวแปรเหมือนภาษาอื่นๆ

ส่วนถ้ารู้สึกไม่สะดวกที่จะเขียนอย่างข้างบน ก็สามารถใช้ grave accent (`) ล้อมรอบชื่อฟังก์ชัน เพื่อให้มันทำงานเป็น infix แบบเดียวกับ operator พวกนั้นได้ (จะใช้ได้ก็ต่อเมื่อเป็นฟังก์ชันที่รับตัวแปร 2 ตัวเท่านั้น)

ข้อแตกต่างอีกอย่างจาก / คือ div จะรับตัวแปรทั้ง 2 ตัวเป็นจำนวนเต็มเท่านั้น

และเมื่อต้องการหารเก็บเศษ ก็ใช้ฟังก์ชัน mod นั่นเอง



ส่วนการยกกำลังก็เช่นเดียวกับการหาร คือมี operator 2 แบบให้เลือกใช้

ท้ายนี้ ถึงแม้ว่า Haskell จะไม่ใช้วงเล็บเพื่อส่งตัวแปรให้ฟังก์ชัน แต่วงเล็บก็สามารถใช้เพื่อบอกกลุ่มของตัวแปรได้เช่นเดียวกับภาษาทั่วไปครับ

หรือถ้ากลัวงง ก็สามารถประกาศค่าเหล่านั้นเป็นตัวแปร (ค่าคงที่) ได้โดยใช้คำสั่ง let

ย้ำอีกครั้งว่า Haskell เป็นภาษา purely functional เพราะฉะนั้นจะไม่มี operator สำหรับเปลี่ยนแปลงค่าของตัวแปรเหล่านั้นนะครับ

November 30, 2012

Haskell: เกร็ดน่ารู้ก่อนเริ่มใช้งาน

จากตอนที่ผ่านมา จะเห็นว่าแบบ interactive นั้นไม่ต้องเขียน main = do ขึ้นต้น นั่นเป็นเพราะว่าเมื่อเริ่ม ghci เราจะเข้ามาอยู่ด้านในของ main ที่ว่านั้นทันที ซึ่งการเขียน code ภายใน main จะมีกฏที่ต่างออกไปเล็กน้อยด้วย

ความสะดวกอย่างอื่นๆ ของตัว interactive
  • แสดงผลลัพท์จากคำสั่งที่พิมพ์เข้าไปทันที (read-eval-print-loop)
  • ทำ keyword completion ด้วย tab
  • macro สำหรับการ debug โดยใช้เครื่องหมาย colon ตามด้วย command (เช่น :q ที่ได้เจอไปแล้ว)
อย่างไรก็ตาม ตัว interactive นั้นไม่รองรับการเขียนหลายบรรทัดเป็นค่าเริ่มต้น ถ้าต้องการเขียนหลายบรรทัด ให้เริ่มด้วย :{ และขึ้นบรรทัดใหม่ แล้วค่อยเริ่มส่วน code เรียบร้อยแล้วจบด้วยบรรทัดที่มีแต่ :} ครับ

อนึ่ง เครื่องหมายหน้าบรรทัดที่บอกว่ากำลังอยู่ใน interactive จะเขียนว่า Prelude> ซึ่งต่อไปเมื่อทำการ load module เยอะๆ แล้ว ข้อความตรงนี้จะเปลี่ยนไปบอกว่า load อะไรมาแล้วบ้าง (ซึ่งอาจจะยาวมาก) ดังนั้น ที่นี้จะใช้แค่ ghci> แทน (สามารถ set ให้เป็นข้อความนี้ได้ด้วย :set prompt "ghci>" ครับ)



ส่วนการเขียนโปรแกรมเก็บเป็นไฟล์นั้น นอกจากจะใช้ ghc เพื่อ compile เป็น binary code ออกมาทดสอบแล้ว ยังมี runhaskell ที่อ่านไฟล์แล้วรันให้ทันทีโดยไม่สร้างไฟล์พวก .o, .hi หรือตัว binary code ให้ แน่นอนว่ามันจะทำงานได้ช้ากว่าแบบ binary code เพราะไม่โดน optimize ด้วยตัว compiler และยังต้องแปลใหม่ทุกครั้งที่เรียกใช้ครับ

ก็เลือกใช้ ghci, ghc และ runhaskell กันตามความเหมาะสมนะครับ



ด้านนามสกุลไฟล์นอกจาก .hs แล้ว ก็มี .lhs ซึ่งเป็นไฟล์ที่เน้นการเขียนโปรแกรมแบบเอกสาร แล้วแทรก code ตามจุดต่างๆ (literate programming) ตัวอย่างก็เช่น


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

ส่วนการ comment source ใน Haskell แบบบรรทัดเดียวใช้ -- เพื่อ comment ข้อความจนจบบรรทัด และแบบหลายบรรทัดใช้ {- กับ -} ครอบส่วนที่ต้องการ comment

ในที่นี้จะไม่ใช้ comment ให้ดู เนื่องจากตัว syntax highlighter ไม่ระบายสีให้ครับ :P

November 29, 2012

Haskell: สวัสดีโลก

1990 มาตรฐานภาษา Haskell 1.0 ปรากฏตัว
1998 รวบรวมมาตรฐานภาษารุ่นก่อนๆ ได้เป็น Haskell 98
2003 GHC เครื่องมือแปลภาษา Haskell ได้รับความนิยมจนเป็นมาตรฐานกลายๆ
2010 ตัวภาษาเดินทางมาถึงรุ่น Haskell 2010

ชื่อภาษาตั้งเพื่อเป็นเกียรติแก่ Haskell Curry นักคณิตศาสตร์ผู้บุกเบิก combinatory logic ครับ



Haskell เป็นภาษา purely functional ซึ่งทำให้เราไม่สามารถเปลี่ยนค่าตัวแปรหลังจากที่ประกาศมันได้ ส่งผลให้การคำนวณซ้ำแบบ loop ต้องเปลี่ยนไปเขียนในรูป recursion หรือ list comprehension แทน ซึ่งจะช่วยลด side effect อย่างการแชร์ตัวแปรจากที่เดียวกันได้ นอกจากนี้ตัวภาษายังเป็นแบบ lazy evaluation คือจะทำการคำนวณให้เมื่อขอดูผลลัพท์เท่านั้นครับ

โหลดโปรแกรม haskell-platform มาติดตั้งได้จากที่นี่ รองรับทั้ง Windows, Mac และ Linux (สำหรับ Debian ติดตั้งจาก apt-get ได้ด้วย) หรือจะไปทดลองเล่น intepreter ขนาดย่อมผ่านหน้าเว็บก่อนก็ได้



Haskell นั้นมาพร้อมกับ compiler และ interpreter ในตัว ซึ่งทั้งสองแบบนี้จะมีการทำงานแตกต่างกันเล็กน้อย ว่าแล้วก็มาลอง hello กัน โดยเริ่มที่แบบ interpreter ก่อน โดยพิมพ์

เพื่อเข้าสู่ Haskell interpreter ซึ่งมีข้อความต้อนรับดังนี้

พิมพ์

ก็จะพบกับข้อความทักทาย เรียบร้อยแล้วออกโปรแกรมโดยพิมพ์ :q [Enter] หรือป้อน EOF ก็ได้

ส่วนแบบที่ต้อง compile สร้างไฟล์ใหม่ที่มีข้อความดังนี้

เซฟเป็นไฟล์ hello.hs แล้วสั่ง

จะได้ไฟล์ hello มา (ต่างจาก compiler อย่าง gcc ที่จะได้ไฟล์ a.out) และเรียกโปรแกรมโดย

ก็เป็นอันเสร็จพิธี

November 22, 2012

PHP: PDO กับฐานข้อมูล

ในการใช้ PHP ทำงานร่วมกับฐานข้อมูล จำเป็นต้องรู้ภาษา SQL เสียก่อน และต้องรู้ด้วยว่า ฐานข้อมูลที่ต้องทำงานด้วยนั้นเป็นระบบไหน เพราะ PHP มีคำสั่งเฉพาะสำหรับฐานข้อมูลแต่ละระบบแยกกันอยู่

แต่เมื่อมีเทคโนโลยีมากขึ้นระบบฐานข้อมูลมีความหลากหลายมากขึ้น ความคล่องตัวในการย้ายฐานข้อมูลจากระบบหนึ่งไปยังอีกระบบหนึ่งก็ยุ่งยากขึ้น ทาง PHP จึงสร้าง extension ชื่อ PDO (PHP Data Objects) ขึ้นมาเพื่อเป็นตัวกลางในการจัดการฐานข้อมูล โดยโปรแกรมเมอร์แทบไม่ต้องสนใจว่า ระบบฐานข้อมูลที่จะทำงานร่วมกันเป็นแบบไหน

การเชื่อมต่อกับระบบฐานข้อมูลผ่าน PDO ก็ให้สร้างออปเจ็กของคลาสขึ้นมา ตัวอย่างข้างต้นใช้ MySQL แต่ถ้าต้องการเปลี่ยนเป็นอย่างอื่นก็แก้ไขบรรทัดที่ 12 ให้เป็นระบบฐานข้อมูลนั้น ๆ หากไม่มีการใช้คำสั่ง SQL ที่จำเพาะต่อระบบฐานข้อมูลนั้น ๆ ก็จะไม่ต้องแก้ไขโค้ดในส่วนอื่น ๆ อีก ส่วนการปิดการเชื่อมต่อนั้น ตามหลักแล้ว PHP จะปิดการเชื่อมต่อให้โดยอัตโนมัติเมื่อจบสคริปท์ แต่หากต้องการสั่งเองก็ใช้ เมื่อเชื่อมต่อกับฐานข้อมูลได้แล้ว ก็สามารถใช้คำสั่ง SQL จัดการกับฐานข้อมูลได้ 2 วิธี คือ
  • สั่งโดยตรงผ่านฟังชั่น exec() และ query()
  • ใช้ฟังชั่น prepare() และ excute()