<?xml version="1.0" encoding="UTF-8" standalone="no"?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><rss xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd" version="2.0"><channel><title>Tutor0x</title><description>Blog of the geek, by the geek, and for the geek.</description><managingEditor>noreply@blogger.com (nz)</managingEditor><pubDate>Thu, 6 Nov 2025 17:22:59 +0700</pubDate><generator>Blogger http://www.blogger.com</generator><openSearch:totalResults xmlns:openSearch="http://a9.com/-/spec/opensearchrss/1.0/">113</openSearch:totalResults><openSearch:startIndex xmlns:openSearch="http://a9.com/-/spec/opensearchrss/1.0/">1</openSearch:startIndex><openSearch:itemsPerPage xmlns:openSearch="http://a9.com/-/spec/opensearchrss/1.0/">25</openSearch:itemsPerPage><link>http://tutor0x.blogspot.com/</link><language>en-us</language><itunes:explicit>no</itunes:explicit><itunes:subtitle>Blog of the geek, by the geek, and for the geek.</itunes:subtitle><itunes:owner><itunes:email>noreply@blogger.com</itunes:email></itunes:owner><item><title>Haskell: กรองและแปลงค่าสมาชิกใน List</title><link>http://tutor0x.blogspot.com/2012/12/haskell-list_21.html</link><category>Haskell</category><author>noreply@blogger.com (nz)</author><pubDate>Fri, 21 Dec 2012 15:48:00 +0700</pubDate><guid isPermaLink="false">tag:blogger.com,1999:blog-3074227793814140422.post-6713091206229970104</guid><description>โดยทั่วไปแล้ว &lt;code&gt;List&lt;/code&gt; ตั้งต้นมักไม่ค่อยมีประโยชน์ที่จะเอาไปใช้ต่อเท่าไหร่ จนกว่าเราจะเปลี่ยนค่าของสมาชิกบางตัวไปตามเราที่ต้องการ&lt;br /&gt;
&lt;br /&gt;
เราสามารถสร้าง &lt;code&gt;List&lt;/code&gt; ใหม่จากของเดิมได้ โดยคำนวณค่าสมาชิกเก่าทุกตัวภายใต้ฟังก์ชันเดียวกัน วิธีการนี้เรียกว่า &lt;a href="http://en.wikipedia.org/wiki/List_comprehension"&gt;list comprehension&lt;/a&gt; และสามารถทำได้ดังนี้&lt;br /&gt;
&lt;br /&gt;
&lt;script class="brush: python" type="syntaxhighlighter"&gt;
ghci&gt; [2 * x^2 | x &amp;lt;- [1..10]]
[2,8,18,32,50,72,98,128,162,200]
ghci&gt; [[a] ++ [v] | a &amp;lt;- "kg", v &amp;lt;- "aiueo"]
["ka","ki","ku","ke","ko","ga","gi","gu","ge","go"]
&lt;/script&gt;&lt;br /&gt;
นอกจากนี้ เรายังสามารถกรองสมาชิกตัวที่ไม่ต้องการทิ้งก่อนเอาไปคำนวณไปได้ เช่น&lt;br /&gt;
&lt;br /&gt;
&lt;script class="brush: python" type="syntaxhighlighter"&gt;
ghci&gt; [2 * x^2 | x &amp;lt;- [1..10], odd x]
[2,18,50,98,162]
ghci&gt; [2 * x^2 | x &amp;lt;- [1..10], x &amp;lt; 5]
[2,8,18,32]
&lt;/script&gt;&lt;br /&gt;
อย่างไรก็ตาม ถ้าต้องทำงานกับ &lt;code&gt;List&lt;/code&gt; อนันต์ (อย่าง &lt;code&gt;[1..]&lt;/code&gt;) การกรองสมาชิกด้วยวิธีการข้างต้นนี้ไม่พอ ต้องใช้งานร่วมกับ &lt;code&gt;take&lt;/code&gt;, &lt;code&gt;takeWhile&lt;/code&gt; เช่นเดิมครับ&lt;br /&gt;
&lt;br /&gt;
&lt;hr /&gt;&lt;br /&gt;
นอกจาก list comprehension ยังมีทางเลือกที่ช่วยให้ทำงานได้เช่นเดียวกันคือ &lt;code&gt;map&lt;/code&gt; กับ &lt;code&gt;filter&lt;/code&gt; ครับ&lt;br /&gt;
&lt;br /&gt;
&lt;script class="brush: python" type="syntaxhighlighter"&gt;
ghci&gt; map (^2) [1..10]
[1,4,9,16,25,36,49,64,81,100]
ghci&gt; map (*2) (map (^2) [1..10])
[2,8,18,32,50,72,98,128,162,200]
ghci&gt; map (*2) (map (^2) (filter odd [1..10]))
[2,18,50,98,162]
&lt;/script&gt;&lt;br /&gt;
ข้อแตกต่างหลักๆ คือ list comprehension จะทำงานกับ &lt;code&gt;List&lt;/code&gt; หลายๆ อัน (มองในรูป &lt;a href="http://en.wikipedia.org/wiki/Cartesian_product"&gt;Cartesian product&lt;/a&gt;) ได้ง่ายกว่า แต่การใช้ฟังก์ชัน &lt;code&gt;map&lt;/code&gt;, &lt;code&gt;filter&lt;/code&gt; แยกกัน จะเป็นธรรมชาติกว่าเมื่อทำ &lt;code&gt;filter&lt;/code&gt; หลังจาก &lt;code&gt;map&lt;/code&gt; เช่น&lt;br /&gt;
&lt;br /&gt;
&lt;script class="brush: python" type="syntaxhighlighter"&gt;
ghci&gt; filter (/="wu") [[a] ++ [v] | a &amp;lt;- "w", v &amp;lt;- "aeiou"]
["wa","we","wi","wo"]
&lt;/script&gt;&lt;br /&gt;
&lt;hr /&gt;&lt;br /&gt;
ตัวอย่างเลื่องชื่อของ Haskell อย่าง &lt;a href="http://en.wikipedia.org/wiki/Quicksort"&gt;quicksort&lt;/a&gt; ก็สามารถทำโดยใช้เทคนิค &lt;code&gt;filter&lt;/code&gt; ร่วมกับการทำ pattern matching บน &lt;code&gt;List&lt;/code&gt; ดังนี้ครับ&lt;br /&gt;
&lt;br /&gt;
&lt;script class="brush: python" type="syntaxhighlighter"&gt;
quicksort []     = []
quicksort (x:xs) = quicksort lesser ++ [x] ++ quicksort greater
    where lesser  = filter (&amp;lt;x)  xs
          greater = filter (&gt;=x) xs
&lt;/script&gt;</description><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total></item><item><title>Haskell: ทำงานกับ List ที่ยาวเป็นอนันต์</title><link>http://tutor0x.blogspot.com/2012/12/haskell-list_1570.html</link><category>Haskell</category><author>noreply@blogger.com (nz)</author><pubDate>Thu, 13 Dec 2012 10:39:00 +0700</pubDate><guid isPermaLink="false">tag:blogger.com,1999:blog-3074227793814140422.post-1193194234430658707</guid><description>การประกาศ &lt;code&gt;List&lt;/code&gt; นอกจากจะทำได้ตามวิธีปรกติแล้ว Haskell ยังทำท่านี้ได้อีกด้วย&lt;br /&gt;
&lt;br /&gt;
&lt;script class="brush: python" type="syntaxhighlighter"&gt;
ghci&gt; [1..10]
[1,2,3,4,5,6,7,8,9,10]
ghci&gt; ['a'..'z']
"abcdefghijklmnopqrstuvwxyz"
&lt;/script&gt;&lt;br /&gt;
ค่าที่เพิ่มจะเพิ่มขึ้นครั้งละ 1 หน่วย (ถ้าตัวเลขก็คือ &lt;code&gt;+1&lt;/code&gt; ถ้าเป็นตัวอักษรก็คือตัวอักษรถัดไป) เราสามารถแก้ไขค่าที่จะเพิ่มขึ้นได้โดยบอกสมาชิกตัวถัดไปใน &lt;code&gt;List&lt;/code&gt; นี้แทน&lt;br /&gt;
&lt;br /&gt;
&lt;script class="brush: python" type="syntaxhighlighter"&gt;
ghci&gt; [1,3..20]
[1,3,5,7,9,11,13,15,17,19]
ghci&gt; ['a','f'..'z']
"afkpuz"
&lt;/script&gt;&lt;br /&gt;
สมาชิกตัวสุดท้ายที่บอกขอบเขตบนนั้น อาจอยู่หรือไม่อยู่ใน &lt;code&gt;List&lt;/code&gt; ที่สร้างเสร็จก็ได้ แต่จะไม่มีสมาชิกที่มีค่าใหญ่กว่านี้ครับ&lt;br /&gt;
&lt;br /&gt;
ส่วนการประกาศค่าแบบลดลงนั้น ไม่สามารถบอกแค่ &lt;code&gt;[10..1]&lt;/code&gt; ได้ ต้องบอกสมาชิกตัวถัดมาด้วย&lt;br /&gt;
&lt;br /&gt;
&lt;script class="brush: python" type="syntaxhighlighter"&gt;
ghci&gt; [10,9..1]
[10,9,8,7,6,5,4,3,2,1]
&lt;/script&gt;&lt;br /&gt;
หมายเหตุว่าให้ระวังการประกาศ &lt;code&gt;List&lt;/code&gt; แบบนี้กับเลขทศนิยม เพราะ bug ของตัว Haskell เองทำให้อาจมีสมาชิกที่ใหญ่กว่าขอบเขตบนโผล่มาได้ครับ&lt;br /&gt;
&lt;br /&gt;
อนึ่ง เราสามารถละส่วนขอบเขนบนได้ โดย Haskell จะเอาขอบเขตบนของ type นั้นมาเติมให้เอง เช่น&lt;br /&gt;
&lt;br /&gt;
&lt;script class="brush: python" type="syntaxhighlighter"&gt;
ghci&gt; ['a','z'..]
&lt;/script&gt;&lt;br /&gt;
ปล่อยไว้ซักพัก จะเห็นว่า &lt;code&gt;List&lt;/code&gt; ที่สร้างขึ้นนี้วิ่งไปจบที่ตัวอักษรซักตัวเอง และถ้าสงสัยว่าขอบเขตบนนั้นคืออะไร ก็สามารถหาได้โดย&lt;br /&gt;
&lt;br /&gt;
&lt;script class="brush: python" type="syntaxhighlighter"&gt;
ghci&gt; maxBound :: Char
'\1114111'
ghci&gt; minBound :: Char
'\NUL'
&lt;/script&gt;&lt;br /&gt;
แต่สำหรับข้อมูลบาง type ที่ไม่มีขอบเขตบน (เช่น &lt;code&gt;Integer&lt;/code&gt;) เมื่อสั่ง &lt;code&gt;[1..]&lt;/code&gt; ตัวเลขจะวิ่งขี้นไปเรื่อยๆ ไม่มีที่สิ้นสุดครับ (เป็น &lt;code&gt;List&lt;/code&gt; ที่ยาวเป็นอนันต์)&lt;br /&gt;
&lt;br /&gt;
&lt;hr /&gt;&lt;br /&gt;
&lt;code&gt;List&lt;/code&gt; ที่ยาวเป็นอนันต์อาจฟังดูไม่มีประโยชน์ เพราะมันคล้ายว่าเราสั่งให้โปรแกรมไปสร้าง &lt;code&gt;List&lt;/code&gt; ที่ไม่มีวันเสร็จ (และโปรแกรมก็จะไม่สามารถไปทำงานอย่างอื่นต่อได้) อย่างไรก็ตาม การดึงสมาชิกเพียงบางส่วนจากออกมานั้นเป็นไปได้ใน Haskell เพราะมันจะไม่พยายามสร้าง &lt;code&gt;List&lt;/code&gt; นั้นๆ จนเสร็จ แต่จะสร้างเพียงเท่าที่เราขอไปใช้ต่อเท่านั้น&lt;br /&gt;
&lt;br /&gt;
ฟังก์ชันที่ใช้เพื่อขอสมาชิกเพียงไม่กี่ตัวแรกของ &lt;code&gt;List&lt;/code&gt; จากทางด้านหน้าคือ &lt;code&gt;take&lt;/code&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;script class="brush: python" type="syntaxhighlighter"&gt;
ghci&gt; take 10 [1,3..]
[1,3,5,7,9,11,13,15,17,19]
&lt;/script&gt;&lt;br /&gt;
ส่วน &lt;code&gt;drop&lt;/code&gt; นั้นจะใช้เพื่อทิ้งสมาชิกตัวหน้าออกไป&lt;br /&gt;
&lt;br /&gt;
&lt;script class="brush: python" type="syntaxhighlighter"&gt;
ghci&gt; drop 5 [1..10]
[6,7,8,9,10]
&lt;/script&gt;&lt;br /&gt;
(&lt;code&gt;drop&lt;/code&gt; เพียงอย่างเดียวนั้นไม่ค่อยมีประโยชน์กับ &lt;code&gt;List&lt;/code&gt; ที่ยาวเป็นอนันต์ครับ)&lt;br /&gt;
&lt;br /&gt;
ฟังก์ชันอีกกลุ่มที่ทำหน้าที่เช่นเดียวกันนี้ เพียงแต่เปลี่ยนจากจำนวนสมาชิกที่ต้องการแน่นอน ไปเป็นการตรวจสอบค่าสมาชิกว่าตรงเงื่อนไขหรือยัง คือ &lt;code&gt;takeWhile&lt;/code&gt; และ &lt;code&gt;dropWhile&lt;/code&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;script class="brush: python" type="syntaxhighlighter"&gt;
ghci&gt; takeWhile (&lt;10) [1,3..20]
[1,3,5,7,9]
ghci&gt; dropWhile (/=3) [1,2,3,4,5,4,3,2,1]
[3,4,5,4,3,2,1]
&lt;/script&gt;&lt;br /&gt;
ย้ำอีกทีว่าฟังก์ชันพวกนี้จะเริ่มทำงานจากด้านหัว และคืนค่าทันทีเมื่อเงื่อนไขครบ เห็นได้จาก &lt;code&gt;dropWhile (/=3)&lt;/code&gt; ที่ทิ้งเลข &lt;code&gt;[1,2]&lt;/code&gt; เฉพาะทางด้านหัวเท่านั้น&lt;br /&gt;
&lt;br /&gt;
&lt;hr /&gt;&lt;br /&gt;
นอกจากจะใช้การประกาศ &lt;code&gt;List&lt;/code&gt; ตามด้านบนเพื่อสร้าง &lt;code&gt;List&lt;/code&gt; ที่ยาวอนันต์ได้แล้ว ยังสามารถสร้าง &lt;code&gt;List&lt;/code&gt; ที่ยาวเป็นอนันต์โดยใช้ฟังก์ชันเหล่านี้&lt;br /&gt;
&lt;br /&gt;
&lt;code&gt;cycle&lt;/code&gt; รับตัวแปรเป็น &lt;code&gt;List&lt;/code&gt; ที่จะเอามาทำซ้ำเรื่อยๆ&lt;br /&gt;
&lt;br /&gt;
&lt;script class="brush: python" type="syntaxhighlighter"&gt;
ghci&gt; take 15 (cycle "kak ")
"kak kak kak kak"
&lt;/script&gt;&lt;br /&gt;
ส่วน &lt;code&gt;repeat&lt;/code&gt; จะรับตัวแปรคือสมาชิกตัวเดียวของ &lt;code&gt;List&lt;/code&gt; ที่จะเอาไปทำซ้ำๆ แต่ถ้ารู้ขนาดที่แน่นอนอยู่แล้ว สามารถใช้ฟังก์ชัน &lt;code&gt;replicate&lt;/code&gt; แทนได้&lt;br /&gt;
&lt;br /&gt;
&lt;script class="brush: python" type="syntaxhighlighter"&gt;
ghci&gt; take 3 (repeat 5)
[5,5,5]
ghci&gt; replicate 3 5
[5,5,5]
&lt;/script&gt;</description><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total></item><item><title>Haskell: เก็บข้อมูลชุดด้วย List</title><link>http://tutor0x.blogspot.com/2012/12/haskell-list.html</link><category>Haskell</category><author>noreply@blogger.com (nz)</author><pubDate>Wed, 12 Dec 2012 03:47:00 +0700</pubDate><guid isPermaLink="false">tag:blogger.com,1999:blog-3074227793814140422.post-9177521871569146523</guid><description>การสร้าง &lt;code&gt;List&lt;/code&gt; ใน Haskell โดยพื้นฐานก็จะมีหน้าตาคล้ายภาษาขั้นสูงทั่วไป คือใช้วงเล็บปีกแข็งครอบสมาชิกไว้เช่นนี้&lt;br /&gt;
&lt;br /&gt;
&lt;script class="brush: python" type="syntaxhighlighter"&gt;
ghci&gt; [1,2,3]
[1,2,3]
ghci&gt; ['h','e','l','l','o']
"hello"
&lt;/script&gt;&lt;br /&gt;
อย่างไรก็ตาม สมาชิกใน &lt;code&gt;List&lt;/code&gt; ทุกตัวต้องเป็น type เดียวกันเท่านั้น เช่นเดียวกับ &lt;code&gt;String&lt;/code&gt; ที่มีสมาชิกทุกตัวเป็น &lt;code&gt;Char&lt;/code&gt; นั่นเอง&lt;br /&gt;
&lt;br /&gt;
การเพิ่มสมาชิกให้ &lt;code&gt;List&lt;/code&gt; นอกจากจะทำผ่าน &lt;code&gt;++&lt;/code&gt; ได้แล้ว ยังสามารถทำผ่าน &lt;code&gt;:&lt;/code&gt; ได้อีกด้วย โดยฝั่งซ้ายของ &lt;code&gt;:&lt;/code&gt; คือสมาชิกที่จะเพิ่ม และฝั่งขวาคือ &lt;code&gt;List&lt;/code&gt; ตั้งต้น ผลลัพท์จะเป็น &lt;code&gt;List&lt;/code&gt; ตั้งต้นที่มีสามาชิกใหม่ด้านหัว&lt;br /&gt;
&lt;br /&gt;
&lt;script class="brush: python" type="syntaxhighlighter"&gt;
ghci&gt; 1:[]
[1]
ghci&gt; 4:[8,15,16,23,42]
[4,8,15,16,23,42]
ghci&gt; 'h':'e':'l':'l':'o':[]
"hello"
&lt;/script&gt;&lt;br /&gt;
&lt;code&gt;List&lt;/code&gt; ใน Haskell นั้น แท้จริงแล้วถูกออกแบบมาเป็น stack โดยด้านที่รับ-ส่งสมาชิกคือด้านหัว (ฝั่งซ้ายมือ) ดังนั้นเรามักจะเพิ่มสมาชิกตัวใหม่ๆ โดย &lt;code&gt;:&lt;/code&gt; มากกว่าที่จะใช้ &lt;code&gt;++&lt;/code&gt; เพิ่มสมาชิกต่อหลังครับ (มีผลต่อความเร็ว)&lt;br /&gt;
&lt;br /&gt;
&lt;hr /&gt;&lt;br /&gt;
เมื่อต้องการดึงหัว &lt;code&gt;List&lt;/code&gt; ออกมาใช้ ทำได้โดยฟังก์ชัน &lt;code&gt;head&lt;/code&gt; หรือเก็บสมาชิกทุกตัวยกเว้นหัวก็ใช้ &lt;code&gt;tail&lt;/code&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;script class="brush: python" type="syntaxhighlighter"&gt;
้ghci&gt; head "hello"
'h'
้ghci&gt; tail "hello"
"ello"
&lt;/script&gt;&lt;br /&gt;
แม้เราจะไม่ค่อยยุ่งกับสมาชิกตัวท้ายสุดซักเท่าไหร่ แต่ถ้าต้องการสมาชิกตัวสุดท้าย หรือต้องการสมาชิกทุกตัวยกเว้นท้ายสุด ก็สามาถทำได้ผ่าน &lt;code&gt;last&lt;/code&gt;, &lt;code&gt;init&lt;/code&gt; ตามลำดับ&lt;br /&gt;
&lt;br /&gt;
&lt;script class="brush: python" type="syntaxhighlighter"&gt;
ghci&gt; last [4,8,15,16,23,42]
42
ghci&gt; init [4,8,15,16,23,42]
[4,8,15,16,23]
&lt;/script&gt;&lt;br /&gt;
ข้อควรระวังคือการดำเนินการพวกนี้ ไม่สามารถทำได้กับ &lt;code&gt;List&lt;/code&gt; ที่ไม่มีสมาชิกเลย ซึ่งเราสามารถตรวจว่ามีสมาชิกหรือไม่ได้โดยคำสั่ง &lt;code&gt;null&lt;/code&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;script class="brush: python" type="syntaxhighlighter"&gt;
ghci&gt; null ""
True
&lt;/script&gt;&lt;br /&gt;
ส่วนการดึงสมาชิก ณ ตำแหน่งใดๆ ออกมา ทำได้ผ่านเครื่องหมาย &lt;code&gt;!!&lt;/code&gt; เช่นนี้ครับ&lt;br /&gt;
&lt;br /&gt;
&lt;script class="brush: python" type="syntaxhighlighter"&gt;
ghci&gt; [4,8,15,16,23,42] !! 0
4
ghci&gt; [4,8,15,16,23,42] !! 5
42
&lt;/script&gt;&lt;br /&gt;
แน่นอนว่ามันจะให้ error ถ้าส่วน index นั้นใหญ่เกินกว่า &lt;code&gt;List&lt;/code&gt; เราสามารถหาขนาดได้โดยฟังก์ชัน &lt;code&gt;length&lt;/code&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;script class="brush: python" type="syntaxhighlighter"&gt;
ghci&gt; length [4,8,15,16,23,42]
6
ghci&gt; length []
0
&lt;/script&gt;&lt;br /&gt;
ส่วนถ้าจะตรวจสอบว่ามีสมาชิกที่เราอยากรู้อยู่ใน &lt;code&gt;List&lt;/code&gt; นั้นหรือเปล่า ก็ทำได้ผ่านฟังก์ชัน &lt;code&gt;elem&lt;/code&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;script class="brush: python" type="syntaxhighlighter"&gt;
ghci&gt; 13 `elem` [4,8,15,16,23,42]
False
&lt;/script&gt;</description><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total></item><item><title>Haskell: ข้อความและ IO เบื้องต้น</title><link>http://tutor0x.blogspot.com/2012/12/haskell-io.html</link><category>Haskell</category><author>noreply@blogger.com (nz)</author><pubDate>Tue, 11 Dec 2012 04:37:00 +0700</pubDate><guid isPermaLink="false">tag:blogger.com,1999:blog-3074227793814140422.post-2802240041009448165</guid><description>ใน Haskell จะแบ่งข้อมูลตัวอักษรเป็น 2 แบบ ได้แก่ &lt;code&gt;Char&lt;/code&gt; (อักษร 1 ตัว) ที่ประกาศโดยใช้ single quote ส่วน &lt;code&gt;String&lt;/code&gt; (อักษรหลายตัว) ประกาศโดยใช้ double quote&lt;br /&gt;
&lt;br /&gt;
&lt;script class="brush: python" type="syntaxhighlighter"&gt;
ghci&gt; let c = 'a'
ghci&gt; let s = "abc"
&lt;/script&gt;&lt;br /&gt;
อย่างไรก็ตาม ถ้าลองตรวจสอบ type ของ String จะเห็นแบบนี้&lt;br /&gt;
&lt;br /&gt;
&lt;script class="brush: python" type="syntaxhighlighter"&gt;
ghci&gt; :t "this is a string"
"this is a string" :: [Char]
&lt;/script&gt;&lt;br /&gt;
วงเล็บปีกแข็งที่ครอบ &lt;code&gt;Char&lt;/code&gt; นั้นบอกว่า &lt;code&gt;String&lt;/code&gt; เป็นข้อมูลแบบ &lt;code&gt;List&lt;/code&gt; ของ &lt;code&gt;Char&lt;/code&gt; (คือการเอา &lt;code&gt;Char&lt;/code&gt; หลายๆ ตัวมาต่อกัน)&lt;br /&gt;
&lt;br /&gt;
การเชื่อม &lt;code&gt;String&lt;/code&gt; เข้าด้วยกัน ทำได้โดยวางเครื่องหมาย &lt;code&gt;++&lt;/code&gt; ไว้ระหว่างข้อความ 2 ข้อความ&lt;br /&gt;
&lt;br /&gt;
&lt;script class="brush: python" type="syntaxhighlighter"&gt;
ghci&gt; "Hello " ++ "Nick" ++ "."
"Hello Nick."
&lt;/script&gt;&lt;br /&gt;
อย่างไรก็ตาม การเชื่อม &lt;code&gt;String&lt;/code&gt; กับ &lt;code&gt;Char&lt;/code&gt; ต้องแปลง type ของ &lt;code&gt;Char&lt;/code&gt; ให้เป็น &lt;code&gt;String&lt;/code&gt; เสียก่อน&lt;br /&gt;
&lt;br /&gt;
&lt;script class="brush: python" type="syntaxhighlighter"&gt;
ghci&gt; "Grade: " ++ ['A']
"Grade: A"
&lt;/script&gt;&lt;br /&gt;
ถ้าต้องการแสดงตัวเลข (และข้อมูลชนิดอื่นๆ) ให้ใช้ฟังก์ชัน &lt;code&gt;show&lt;/code&gt; แทน&lt;br /&gt;
&lt;br /&gt;
&lt;script class="brush: python" type="syntaxhighlighter"&gt;
ghci&gt; "Point: " ++ show 87.5
"Point: 87.5"
&lt;/script&gt;&lt;br /&gt;
ส่วนการแปลง type จากข้อความไปเป็น type อื่นเพื่อนำไปคำนวณต่อ สามารถทำได้ผ่านฟังก์ชัน &lt;code&gt;read&lt;/code&gt; เช่นนี้&lt;br /&gt;
&lt;br /&gt;
&lt;script class="brush: python" type="syntaxhighlighter"&gt;
ghci&gt; read "23" + 19
42
&lt;/script&gt;&lt;br /&gt;
แต่การสั่ง &lt;code&gt;read "23"&lt;/code&gt; เพียงอย่างเดียวจะเกิด error เพราะตัวแปรนั้นจะหา type ไม่ได้ (เนื่องจากไม่รู้ว่าจะถูกเอาไปใช้ทำอะไรต่อ)&lt;br /&gt;
&lt;br /&gt;
ทางออกคือถ้ารู้ type ที่จะเอาไปใช้ต่อแน่นอน ก็กำหนดลงไปได้เลย &lt;br /&gt;
&lt;br /&gt;
&lt;script class="brush: python" type="syntaxhighlighter"&gt;
ghci&gt; read "23" :: Float
23.0
&lt;/script&gt;&lt;br /&gt;
&lt;hr /&gt;&lt;br /&gt;
เนื่องจากหลักการของภาษาเชิง functional นั้นบอกว่า ฟังก์ชันใดๆ ที่เรียกขึ้นมาโดยส่งผ่านตัวแปรเดิมเข้าไป ผลลัพท์ก็ต้องออกมาเหมือนเดิมเสมอ&lt;br /&gt;
&lt;br /&gt;
ตัวแปรของฟังก์ชันในที่นี้ คือตัวแปรที่กำหนดโดยโปรแกรมเมอร์ ไม่ใช่ IO จากฝั่งผู้ใช้ ดังนั้นถ้ายึดตามหลักนี้ โปรแกรมเดียวกันจะให้ผลลัพท์เดิมทุกครั้ง (เพราะ IO ที่รับมาจากผู้ใช้ไม่มีความหมาย) Haskell แก้ปัญหานี้โดยการนิยามฟังก์ชันสำหรับจัดการ IO แยกออกมาโดยเฉพาะ&lt;br /&gt;
&lt;br /&gt;
เมื่อต้องการรับข้อความเป็นบรรทัดจากผู้ใช้ ทำได้โดยฟังก์ชัน &lt;code&gt;getLine&lt;/code&gt; ดังนี้&lt;br /&gt;
&lt;br /&gt;
&lt;script class="brush: python" type="syntaxhighlighter"&gt;
ghci&gt; input &amp;lt;- getLine
&lt;/script&gt;&lt;br /&gt;
ฟังก์ชันนี้จะรอเราพิมพ์ข้อความไปเรื่อยๆ จนกว่าจะป้อน EOL ให้ สังเกตว่าการเก็บผลลัพท์นั้นไม่ได้ใช้ &lt;code&gt;let&lt;/code&gt; แล้วตามด้วย &lt;code&gt;=&lt;/code&gt; แล้ว แต่เปลี่ยนมาใช้ &lt;code&gt;&amp;lt;-&lt;/code&gt; แทน ซึ่งเป็นสัญลักษณ์พิเศษสำหรับเก็บค่า &lt;code&gt;String&lt;/code&gt; ที่รับมาจาก IO ครับ&lt;br /&gt;
&lt;br /&gt;
อนึ่ง การพิมพ์ค่าโดยฟังก์ชัน &lt;code&gt;putStrLn&lt;/code&gt; นั้น ตัวแปรแบบต้องเป็นข้อความเท่านั้น ถ้าต้องการพิมพ์ค่าตัวแปรที่ไม่ใช่ข้อความ สามารถใช้ฟังก์ชัน &lt;code&gt;print&lt;/code&gt; แทนได้&lt;br /&gt;
&lt;br /&gt;
ตัวอย่างต่อไปนี้เป็นโปรแกรมแบบ IO คอยรับข้อมูลจากผู้ใช้ แล้วคำนวณด้านที่ยาวที่สุดของสามเหลี่ยมมุมฉากครับ&lt;br /&gt;
&lt;br /&gt;
&lt;script class="brush: python" type="syntaxhighlighter"&gt;
main = do
    putStrLn "what is x?"
    x &lt;- getLine
    putStrLn "what is y?"
    y &lt;- getLine
    putStrLn "then z is:"
    print (sqrt ((read x)**2 + (read y)**2))
    main
&lt;/script&gt;
หมายเหตุว่าการ recursive &lt;code&gt;main&lt;/code&gt; นั้นเป็นเรื่องปรกติใน Haskell ครับ</description><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total></item><item><title>Haskell: ฟังก์ชันและขอบเขตของตัวแปร</title><link>http://tutor0x.blogspot.com/2012/12/haskell_7.html</link><category>Haskell</category><author>noreply@blogger.com (nz)</author><pubDate>Fri, 7 Dec 2012 04:20:00 +0700</pubDate><guid isPermaLink="false">tag:blogger.com,1999:blog-3074227793814140422.post-5966578637492968313</guid><description>นอกจากเราจะสร้างฟังก์ชันด้วย if-else แล้ว Haskell ยังมีความสามารถในการทำ pattern matching กับตัวแปรฟังก์ชันได้อีกด้วย&lt;br /&gt;
&lt;br /&gt;
ตัวอย่างฟังก์ชันจากคราวก่อนในแบบ pattern matching&lt;br /&gt;
&lt;br /&gt;
&lt;script class="brush: python" type="syntaxhighlighter"&gt;
logAbs 0 = error "log zero!"
logAbs x = log (abs x)
&lt;/script&gt;&lt;br /&gt;
pattern matching จะช่วยให้อ่านฟังก์ชันที่อยู่ในรูป recursive ง่ายขึ้นมาก&lt;br /&gt;
&lt;br /&gt;
&lt;script class="brush: python" type="syntaxhighlighter"&gt;
fact 0 = 1
fact x = x * fact (x - 1)
&lt;/script&gt;&lt;br /&gt;
แต่ฟังก์ชัน &lt;code&gt;fact&lt;/code&gt; นี้ยังมีปัญหาอยู่ ตรงที่มันจะ terminate ไม่ได้ ถ้าใส่จำนวนเต็มลบเข้าไป&lt;br /&gt;
&lt;br /&gt;
จากบรรทัดที่สอง &lt;code&gt;x&lt;/code&gt; จะไป match กับค่าใดๆ ก็ตามที่ไม่ใช่ &lt;code&gt;0&lt;/code&gt; เราอาจนึกถึงการใช้ if-else เพื่อดักตัวแปรเหมือนที่ผ่านมา อย่างไรก็ตาม Haskell มีสิ่งที่เรียกว่า guard ซึ่งเทียเท่าได้กับ switch-case ในภาษาอื่น โดยสามารถเรียกใช้งานได้เช่นนี้&lt;br /&gt;
&lt;br /&gt;
&lt;script class="brush: python" type="syntaxhighlighter"&gt;
fact 0             = 1
fact x | x &gt; 0     = x * fact (x - 1)
       | otherwise = error "factorial negative number!"
&lt;/script&gt;&lt;br /&gt;
นอกจากนี้ เรายังสามารถระบุ type ฟังก์ชันได้เช่นเดียวกับตัวแปร โดยเพิ่มบรรทัดนี้เข้าไปด้านบนสุดครับ&lt;br /&gt;
&lt;br /&gt;
&lt;script class="brush: python" type="syntaxhighlighter"&gt;
fact :: Integral n =&gt; n -&gt; n
&lt;/script&gt;&lt;br /&gt;
&lt;hr /&gt;&lt;br /&gt;
ด้านขอบเขตของตัวแปรนั้น เราเคยใช้ &lt;code&gt;let&lt;/code&gt; เก็บค่าตัวแปรที่คำนวณเอาไว้ก่อนมาแล้ว ซึ่งนี่เป็นคำสั่งพิเศษเฉพาะบน &lt;code&gt;ghci&lt;/code&gt; เท่านั้น เมื่อเขียนเป็นฟังก์ชันจะต้องมีส่วน &lt;code&gt;in&lt;/code&gt; เพื่อบอกขอบเขตของตัวแปรที่โดนประกาศด้วย &lt;code&gt;let&lt;/code&gt; เสมอ&lt;br /&gt;
&lt;br /&gt;
&lt;script class="brush: python" type="syntaxhighlighter"&gt;
fib n = let phi = (1 + sqrt 5) / 2
            psi = (1 - sqrt 5) / 2
        in  (phi ** n - psi ** n) / sqrt 5
&lt;/script&gt;&lt;br /&gt;
เช่นตัวอย่างนี้จะประมาณค่า Fibonacci ในตำแหน่งที่ &lt;code&gt;n&lt;/code&gt; โดยคำนวณค่า &lt;code&gt;phi&lt;/code&gt; กับ &lt;code&gt;psi&lt;/code&gt; เก็บไว้ก่อน ซึ่งมันจะถูกนำไปใช้ได้ในหลังจาก &lt;code&gt;in&lt;/code&gt; ตรงบรรทัดที่ 3 เท่านั้นครับ&lt;br /&gt;
&lt;br /&gt;
นอกจากการประกาศด้วย &lt;code&gt;let-in&lt;/code&gt; แล้ว ยังมีอีกวิธีคือใช้ &lt;code&gt;where&lt;/code&gt; ซึ่งคราวนี้ตัวแปรที่ถูกประกาศจะเห็นได้ทั้งฟังก์ชัน รวมถึงส่วน guard เพื่อทำ switch-case อีกด้วย&lt;br /&gt;
&lt;br /&gt;
&lt;script class="brush: python" type="syntaxhighlighter"&gt;
grade mean sd point
    | aboveMean &gt; 2 * sd = "A"
    | aboveMean &gt; 1 * sd = "B"
    | belowMean &gt; 2 * sd = "F"
    | belowMean &gt; 1 * sd = "D"
    | otherwise          = "C"
    where aboveMean = point - mean
          belowMean = mean - point
&lt;/script&gt;&lt;br /&gt;
สิ่งที่ต้องระวังในการเขียนหลายบรรทัดคือการ indent (จัดย่อหน้า) สังเกตว่าประโยคหลัง &lt;code&gt;where&lt;/code&gt; หรือ &lt;code&gt;let&lt;/code&gt; นั้นต้อง indent ให้เท่ากัน เช่นเดียวกับส่วน &lt;code&gt;let&lt;/code&gt; และ &lt;code&gt;in&lt;/code&gt; ครับ&lt;br /&gt;
&lt;br /&gt;
ด้านการออกแบบลำดับตัวแปรของฟังก์ชันนั้น จะให้ตัวแปรแรกๆ เป็นตัวแปรที่เปลี่ยนค่าไม่บ่อย เนื่องจากเราสามารถทำ partial application เพื่อสร้างฟังก์ชันที่มี initial value ได้เช่นนี้&lt;br /&gt;
&lt;br /&gt;
&lt;script class="brush: python" type="syntaxhighlighter"&gt;
ghci&gt; let gradeMath = grade 55 12.5
ghci&gt; let gradeChem = grade 70 10.0
ghci&gt; gradeMath 80
"B"
ghci&gt; gradeChem 80
"C"
&lt;/script&gt;</description><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total></item><item><title>PHP: ระบบสมาชิก - log in, log out</title><link>http://tutor0x.blogspot.com/2012/12/php-log-in-log-out.html</link><category>PHP</category><author>noreply@blogger.com (Unknown)</author><pubDate>Thu, 6 Dec 2012 13:40:00 +0700</pubDate><guid isPermaLink="false">tag:blogger.com,1999:blog-3074227793814140422.post-1210925779499985727</guid><description>คราวก่อน เขียนถึงระบบสมาชิกส่วนแรกซึ่งก็คือ &lt;a href="http://tutor0x.blogspot.com/2012/12/php.html"&gt;การสมัครสมาชิก&lt;/a&gt; คราวนี้มาดูการ log in กับ log out กันบ้าง เริ่มต้นจากสร้างแบบฟอร์มสำหรับ log in กันก่อน  &lt;script class="brush: php" type="syntaxhighlighter"&gt;
&lt;!-- FILE: login.html --&gt;
&lt;form id="login" method="post" action="login.php"&gt;
    &lt;label for="username"&gt;User:&lt;/label&gt;
    &lt;input type="text" id="username" name="username" /&gt;
    &lt;label for="password"&gt;Pass:&lt;/label&gt;
    &lt;input type="password" id="password" name="password" /&gt;

    &lt;input type="submit" id="login" name="login" value="Log in" /&gt;
&lt;/form&gt;&lt;/script&gt;  แบบฟอร์มก็แบบเดียวกับที่พบได้ตามเว็บไซต์ทั่วไป ส่วน .php ที่ใช้ในการ log in จะเริ่มต้นด้วยการตรวจสอบเบื้องต้นก่อนว่า ผู้ใช้ลืมกรอกข้อมูล หรือเปล่า  &lt;script class="brush: php" type="syntaxhighlighter"&gt;
&lt;?php
// FILE: login.php

$error = false;

// get log in information via post
$u_name = $_POST['username'];
$u_pass = $_POST['password'];

// check empty input
if (empty($u_name) || empty($u_pass)) {
 $error = true;
}

if (!$error) {
    // everything fine, check user info in database
}
else {
    // empty username or password, tell the user
    echo 'Invalid username or password.';
}
&lt;/script&gt;

ถ้าทุกอย่างไม่มีปัญหาอะไร ก็มาตรวจสอบบัญชีผู้ใช้ในฐานข้อมูล โดยใช้การเชื่อมต่อผ่าน &lt;a href="http://tutor0x.blogspot.com/2012/11/php-pdo.html"&gt;PDO&lt;/a&gt; เหมือนเดิม ซึ่งตอนที่ตรวจสอบรหัสผ่านนั้น ในตอนสมัครสมาชิก เราใช้การ hash และ salt ในการเก็บข้อมูลของรหัสผ่าน ในขั้นตอน log in เราก็จะต้องแปลงรหัสผ่านให้กลายเป็น hash ที่ถูกต้องด้วย
&lt;script class="brush: php" type="syntaxhighlighter"&gt;
// FILE: login.php
.
.
.

if (!$error) {
 // everything fine, check user info in database

 // db info
 $db_host = 'localhost';
 $db_name = 'tutor0x';
 $db_user = 'user0x';
 $db_pass = 'pass0x';
 
 // connect to database
 try {
  $conn = new PDO("mysql:host=$db_host; dbname=$db_name", $db_user, $db_pass);
  
  $conn-&gt;exec("SET CHARACTER SET utf8");
  
  // prepare checking
  $user = array(
    'name' =&gt; $u_name,
    // we use this salt, we must check with this salt
    'pass' =&gt; sha1('NaCl' . $u_pass . md5($u_pass)),
    );
  
  // prepare sql
  $result = $conn-&gt;prepare("SELECT * FROM members WHERE username=:name AND password=:pass");

  // filled prepared sql statement with $user
  $result-&gt;execute($user);

  // row count must == 1
  if ($result !== false &amp;&amp; $result-&gt;rowCount() == 1) {

   // redirect to other page (member.php)
   // warning: there must no another output before this, otherwise it might failed
   header('Location: member.php');
  }
  else {
   echo 'Invalid username or password.';
  }
 }
 catch (PDOException $e) {
  echo $e-&gt;getMessage();
 }
}
&lt;/script&gt;  ตอนนี้เราสามารถ log in เข้ามาได้แล้ว แต่ผู้ใช้ต้อง log in ใหม่ทุกครั้งเวลาเปลี่ยนหน้า อันนี้ต้องใช้ &lt;a href="http://tutor0x.blogspot.com/2012/07/php-session-cookie.html"&gt;&lt;code&gt;session&lt;/code&gt;&lt;/a&gt; เข้ามาช่วยในการจดจำผู้ใช้&lt;br /&gt;
&lt;br /&gt;
&lt;a name='more'&gt;&lt;/a&gt; เริ่มต้นด้วยการเพิ่ม &lt;code&gt;session_start()&lt;/code&gt; ไว้ในส่วนบนสุดของ .php  &lt;script class="brush: php" type="syntaxhighlighter"&gt;
&lt;?php
//FILE: login.php

session_start();

$error = false;

.
.
.
&lt;/script&gt;

ต่อมาก็เพิ่มโค้ดให้เก็บค่าลง session เข้าไปก่อนที่จะ redirect ไปยังหน้าอื่น

&lt;script class="brush: php" type="syntaxhighlighter"&gt;
// FILE: login.php
.
.
.

// row count must == 1
if ($result !== false &amp;&amp; $result-&gt;rowCount() == 1) {
 // fetch data
 $data = $result-&gt;fetch();

 // saved to session
 SESSION['username'] = $data['username'];
 SESSION['email'] = $data['email'];

 // redirect to other page (member.php)
 // warning: there must no another output before this, otherwise it might failed
 header('Location: member.php');
}
else {
 echo 'Invalid username or password.';
}

.
.
.
&lt;/script&gt;  และเพื่อไม่ให้มีการ log in ซ้ำซ้อน ซึ่งอาจจะนำปัญหามาให้ ก็ให้ตรวจสอบก่อนว่ามีการ log in อยู่แล้วหรือไม่เสียก่อน ในตอนเริ่มแรก  &lt;script class="brush: php" type="syntaxhighlighter"&gt;
&lt;?php
//FILE: login.php

session_start();

// if already logged in redirect
if (isset($_SESSION['username'])) {
 header('Location: member.php');
}

$error = false;

.
.
.
&lt;/script&gt;

ส่วนในหน้าอื่น ๆ ที่จำเป็นต้อง log in ก่อน เพื่อแสดงข้อมูลออกมาก็ให้ตรวจสอบค่า &lt;code&gt;$_SESSION['username']&lt;/code&gt; ดูว่ามีการ log in หรือไม่ ถ้ามีก็ดึงข้อมูลมาตามปกติ แต่ถ้าไม่มีจะบังคับให้ log in เสียก่อน หรือแสดงข้อมูลที่แตกต่างกันออกไป อันนี้ก็แล้วแต่จะออกแบบ

&lt;script class="brush: php" type="syntaxhighlighter"&gt;
&lt;?php
// FILE: member.php

// always start with this
session_start();

// check log in status
if (isset($_SESSION['username'])) {
 // do anything you want
 echo 'Hello ' . $_SESSION['username'] . ' (' . $_SESSION['email'] . ')';
 echo '
';
 echo '&lt;a href="logout.php"&gt;Log out&lt;/a&gt;';
}
else {
 echo 'Please log in!.';
}
&lt;/script&gt;  ส่วนการ logout นั้นทำได้ง่าย ๆ ด้วยคำสั่ง &lt;code&gt;session_destroy()&lt;/code&gt; ทุกอย่างก็หายไป  &lt;script class="brush: php" type="syntaxhighlighter"&gt;
&lt;?php
// FILE: logout.php

session_start();
session_destroy();

echo 'Logged out';
&lt;/script&gt;

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

ที่ผ่านมาจะเห็นว่าไม่มีการพูดถึง &lt;a href="https://en.wikipedia.org/wiki/SQL_injection"&gt;SQL Injection&lt;/a&gt; เลยเพราะว่า เราใช้ฟังชั่น &lt;code&gt;PDO::prepare()&lt;/code&gt; ในการเตรียมข้อมูล ตราบใดที่ไม่มีบั๊กในฟังชั่นนี้ ฐานข้อมูลของเรายังปลอดภัยอยู่</description><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total></item><item><title>Haskell: Boolean และ Control Flow</title><link>http://tutor0x.blogspot.com/2012/12/haskell-boolean-control-flow.html</link><category>Haskell</category><author>noreply@blogger.com (nz)</author><pubDate>Tue, 4 Dec 2012 16:35:00 +0700</pubDate><guid isPermaLink="false">tag:blogger.com,1999:blog-3074227793814140422.post-8965599861309637865</guid><description>ค่าความจริงใน Haskell มีเพียงแค่ &lt;code&gt;True&lt;/code&gt; กับ &lt;code&gt;False&lt;/code&gt; เท่านั้น (ไม่สามารถใช้ &lt;code&gt;0&lt;/code&gt; หรือค่าว่างแบบอื่นๆ แทน &lt;code&gt;False&lt;/code&gt; ได้)&lt;br /&gt;
&lt;br /&gt;
ฟังก์ชันสำหรับตรวจสอบความเท่ากัน ใช้ &lt;code&gt;==&lt;/code&gt; (เท่ากัน) กับ &lt;code&gt;/=&lt;/code&gt; (ไม่เท่ากัน) ส่วนฟังก์ชันสำหรับการตรวจสอบลำดับก็ได้แก่ &lt;code&gt;&amp;lt;=&lt;/code&gt; (น้อยกว่าเท่ากับ), &lt;code&gt;&amp;lt;&lt;/code&gt; (น้อยกว่า), &lt;code&gt;&amp;gt;&lt;/code&gt; (มากกว่า), &lt;code&gt;&amp;gt;=&lt;/code&gt; (มากกว่าเท่ากับ)&lt;br /&gt;
&lt;br /&gt;
&lt;script class="brush: python" type="syntaxhighlighter"&gt;
ghci&gt; 1 == 1
True
ghci&gt; 0 /= 42
True
&lt;/script&gt;&lt;br /&gt;
logic สำหรับเชื่อมค่าความจริงเหล่านี้ได้แก่ &lt;code&gt;&amp;&amp;&lt;/code&gt; (และ), &lt;code&gt;||&lt;/code&gt; (หรือ), &lt;code&gt;not&lt;/code&gt; (นิเสธ)&lt;br /&gt;
&lt;br /&gt;
&lt;script class="brush: python" type="syntaxhighlighter"&gt;
ghci&gt; let x = 42
ghci&gt; 1 &amp;lt; x &amp;&amp; x &amp;lt;= 100
True
&lt;/script&gt;&lt;br /&gt;
สาเหตุที่นิเสธไม่ใช้สัญลักษณ์เช่นเดียวกับการดำเนินการอื่นๆ เพราะฟังก์ชันใน Haskell จะเขียนแทนด้วยสัญลักษณ์ได้ มันต้องเป็นฟังก์ชัน 2 ตัวแปรและทำหน้าที่เป็น infix เท่านั้นครับ&lt;br /&gt;
&lt;br /&gt;
&lt;hr /&gt;&lt;br /&gt;
ด้วยความที่เป็นภาษา functional ทุกๆ expression จะต้องคืนค่ากลับมาเสมอ ทำให้การใช้ if ใน Haskell ต้องมีส่วน else ตามท้ายตลอด&lt;br /&gt;
&lt;br /&gt;
&lt;script class="brush: python" type="syntaxhighlighter"&gt;
ghci&gt; let x = -3.0
ghci&gt; if x /= 0 then log (abs x) else 0
1.0986122886681098
&lt;/script&gt;&lt;br /&gt;
ถ้าต้องการใช้แค่ if อย่างเดียว และบังคับโปรแกรมให้หยุดทำงานเมื่อเจอเงื่อนไขที่ผิด ก็สามารถใช้ฟังก์ชัน &lt;code&gt;error&lt;/code&gt; แบบนี้แทนได้&lt;br /&gt;
&lt;br /&gt;
&lt;script class="brush: python" type="syntaxhighlighter"&gt;
ghci&gt; let x = 0.0
ghci&gt; if x /= 0 then log (abs x) else error "log zero!"
*** Exception: log zero!
&lt;/script&gt;&lt;br /&gt;
ตัวอย่างข้างต้นนี้สามารถแยกเขียนหลายบรรทัดให้อ่านง่ายขึ้นได้ แต่เนื่องจาก &lt;code&gt;ghci&lt;/code&gt; ไม่สะดวกเมื่อต้องเขียนหลายบรรทัด จะย้ายไปเขียนเป็นฟังก์ชันในไฟล์แทน ดังนี้&lt;br /&gt;
&lt;br /&gt;
&lt;script class="brush: python" type="syntaxhighlighter"&gt;
logAbs x = if x /= 0
    then log (abs x)
    else error "log zero!"
&lt;/script&gt;&lt;br /&gt;
สิ่งที่ต่างไปจากการประกาศฟังก์ชันบน &lt;code&gt;ghci&lt;/code&gt; คือ ไม่ต้องมี &lt;code&gt;let&lt;/code&gt; นำหน้า เนื่องจากฟังก์ชันนี้ไม่ได้ถูกประกาศใน &lt;code&gt;main&lt;/code&gt; ครับ&lt;br /&gt;
&lt;br /&gt;
เซฟเป็นไฟล์ &lt;code&gt;func.hs&lt;/code&gt; แล้วกลับมาที่ &lt;code&gt;ghci&lt;/code&gt; เราจะเรียกฟังก์ชันที่เขียนเก็บด้วยคำสั่ง &lt;code&gt;:l&lt;/code&gt; หรือ &lt;code&gt;:load&lt;/code&gt; ดังนี้&lt;br /&gt;
&lt;br /&gt;
&lt;script class="brush: python" type="syntaxhighlighter"&gt;
ghci&gt; :l func.hs 
[1 of 1] Compiling Main             ( func.hs, interpreted )
Ok, modules loaded: Main.
ghci&gt; logAbs (-3)
1.0986122886681098
&lt;/script&gt;</description><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total></item><item><title>Haskell: ชนิดของฟังก์ชัน</title><link>http://tutor0x.blogspot.com/2012/12/haskell_5464.html</link><category>Haskell</category><author>noreply@blogger.com (nz)</author><pubDate>Mon, 3 Dec 2012 21:20:00 +0700</pubDate><guid isPermaLink="false">tag:blogger.com,1999:blog-3074227793814140422.post-906018027536711077</guid><description>ถ้าลองใช้ &lt;code&gt;:t&lt;/code&gt; ตรวจชนิดของฟังก์ชันดูบ้าง จะเห็นแบบนี้&lt;br /&gt;
&lt;br /&gt;
&lt;script class="brush: python" type="syntaxhighlighter"&gt;
ghci&gt; :t fromIntegral
fromIntegral :: (Integral a, Num b) =&gt; a -&gt; b
&lt;/script&gt;&lt;br /&gt;
ส่วนที่บอก type จะอยู่หลังเครื่องหมาย &lt;code&gt;=&gt;&lt;/code&gt; เช่นเคย โดยฝั่งซ้ายของ &lt;code&gt;-&gt;&lt;/code&gt; จะเป็นตัวแปรที่รับเข้ามาในฟังก์ชัน ส่วนฝั่งขวาคือผลลัพท์จากฟังก์ชัน นั่นหมายความว่าฟังก์ชัน &lt;code&gt;fromIntegral&lt;/code&gt; รับตัวแปรใน type class &lt;code&gt;Integral&lt;/code&gt; แล้วได้ผลลัพท์เป็น type class &lt;code&gt;Num&lt;/code&gt;&lt;br /&gt;
&lt;br /&gt;
การเขียนฟังก์ชันนั้น เช่นเดียวกับการประกาศค่าคงที่ คือใช้ &lt;code&gt;let&lt;/code&gt; พร้อมชื่อฟังก์ชันและตัวแปร เช่น&lt;br /&gt;
&lt;br /&gt;
&lt;script class="brush: python" type="syntaxhighlighter"&gt;
ghci&gt; let half x = x / 2
&lt;/script&gt;&lt;br /&gt;
&lt;hr /&gt;&lt;br /&gt;
ทีนี้ลองดูฟังก์ชันของ 2 ตัวแปรกันบ้าง&lt;br /&gt;
&lt;br /&gt;
&lt;script class="brush: python" type="syntaxhighlighter"&gt;
ghci&gt; :t mod
mod :: Integral a =&gt; a -&gt; a -&gt; a
&lt;/script&gt;&lt;br /&gt;
สิ่งที่แตกต่างไปจากภาษา imperative และถือได้ว่าเป็นจุดเด่นของภาษาแบบ functional เลยคือ แทนที่ type ของฟังก์ชัน 2 ตัวแปรจะใช้ช่องว่างคั่นตัวแปร (type น่าจะอยู่ในรูป &lt;code&gt;a a -&gt; a&lt;/code&gt;) แต่ระหว่างตัวแปรกลับใช้สัญลักษณ์ &lt;code&gt;-&gt;&lt;/code&gt; เช่นเดียวกับการบอกผลลัพท์ที่ได้จากฟังก์ชัน&lt;br /&gt;
&lt;br /&gt;
เราอาจลองแบ่งกลุ่มเพื่อความกระจ่างใน type ว่ามันคือ &lt;code&gt;a -&gt; (a -&gt; a)&lt;/code&gt; ซึ่งหมายความว่า ฟังก์ชันนี้เป็นฟังก์ชันที่รับตัวแปร 1 ตัว แล้วให้ผลลัพท์เป็นฟังก์ชันที่รับตัวแปร 1 ตัวแล้วคืนค่าออกมาก็ย่อมได้&lt;br /&gt;
&lt;br /&gt;
นั่นหมายความว่า ฟังก์ชัน 2 ตัวแปร แท้จริงแล้วคือฟังก์ชัน 1 ตัวแปร 2 ชั้น เราจึงสามารถเรียกฟังก์ชันแบบนี้&lt;br /&gt;
&lt;br /&gt;
&lt;script class="brush: python" type="syntaxhighlighter"&gt;
ghci&gt; (mod 123456789) 1009
594
&lt;/script&gt;&lt;br /&gt;
ได้เช่นกัน นี่เป็นเหตุผลว่าทำไม Haskell ถึงไม่ใช้วงเล็บล้อมรอบตัวแปร เราเรียกเทคนิคการทำให้ฟังก์ชันหลายตัวแปรกลายร่างเป็นฟังก์ชันตัวแปรเดียวซ้อนๆ กันเช่นนี้ว่า &lt;a href="http://en.wikipedia.org/wiki/Currying"&gt;currying&lt;/a&gt; และเรียกฟังก์ชันที่รับตัวแปรเข้าไปแล้วบ้างแต่ยังไม่ครบว่า &lt;a href="http://en.wikipedia.org/wiki/Partial_application"&gt;partial application&lt;/a&gt; ครับ&lt;br /&gt;
&lt;br /&gt;
&lt;hr /&gt;&lt;br /&gt;
อนึ่ง เราสามารถเขียนการหารเก็บเศษข้างบนเป็นแบบนี้ &lt;code&gt;123456789 `mod` 1009&lt;/code&gt; และถ้าเราต้องการเอาวงเล็บล้อมรอบ &lt;code&gt;`mod` 1009&lt;/code&gt; ด้านหลัง มันจะกลายเป็นฟังก์ชันที่รับตัวแปรไปแล้ว 1 ตัว และต้องการอีก 1 ที่ต้องทำต่อคือย้ายมันไปไว้ข้างหน้าเท่านั้นเอง&lt;br /&gt;
&lt;br /&gt;
&lt;script class="brush: python" type="syntaxhighlighter"&gt;
ghci&gt; (`mod` 1009) 123456789
594
&lt;/script&gt;&lt;br /&gt;
ซึ่งสามารถจับมาประกาศเป็นฟังก์ชันได้ว่า&lt;br /&gt;
&lt;br /&gt;
&lt;script class="brush: python" type="syntaxhighlighter"&gt;
ghci&gt; let modWithPrime x = (`mod` 1009) x
&lt;/script&gt;&lt;br /&gt;
หรือยิ่งไปกว่านั้น&lt;br /&gt;
&lt;br /&gt;
&lt;script class="brush: python" type="syntaxhighlighter"&gt;
ghci&gt; let modWithPrime = (`mod` 1009)
ghci&gt; modWithPrime 123456789
594
&lt;/script&gt;&lt;br /&gt;
&lt;hr /&gt;&lt;br /&gt;
กลับไปดูฟังก์ชัน &lt;code&gt;half&lt;/code&gt; ที่เขียนไว้ตอนต้นอีกที เราลองเขียนมันใหม่เป็น&lt;br /&gt;
&lt;br /&gt;
&lt;script class="brush: python" type="syntaxhighlighter"&gt;
ghci&gt; let half = (/2)
ghci&gt; half 50
25.0
&lt;/script&gt;&lt;br /&gt;
จะเห็นว่าไม่เพียงแต่ฟังก์ชันเท่านั้น ที่เราสามารถนำวงเล็บไปล้อมรอบได้ แต่นี่ยังรวมไปถึง operator ด้วย นอกจากนี้&lt;br /&gt;
&lt;br /&gt;
&lt;script class="brush: python" type="syntaxhighlighter"&gt;
ghci&gt; :t (/)
(/) :: Fractional a =&gt; a -&gt; a -&gt; a
&lt;/script&gt;&lt;br /&gt;
&lt;br /&gt;
นั่นหมายความว่า operator เหล่านั้นก็ถือเป็นฟังก์ชันเช่นเดียวกันนั่นเอง</description><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total></item><item><title>PHP: ระบบสมาชิก - สมัครสมาชิก</title><link>http://tutor0x.blogspot.com/2012/12/php.html</link><category>PHP</category><author>noreply@blogger.com (Unknown)</author><pubDate>Sun, 2 Dec 2012 16:05:00 +0700</pubDate><guid isPermaLink="false">tag:blogger.com,1999:blog-3074227793814140422.post-7880922058630375476</guid><description>งานการทำงานด้านเว็บด้วยภาษาฝั่งเซิฟเวอร์ มักจะมีความเกี่ยวข้องกับระบบฐานข้อมูลอยู่เสมอ ๆ หนึ่งในนั้นคือ ระบบสมาชิก เว็บหลายเว็บในปัจจุบัน มีการเชื่อมต่อระบบสมาชิกเข้ากับ social network ต่าง ๆ เพื่อความสะดวกให้กับผู้ใช้ แต่ผู้ใช้บางคนอาจจะไม่ต้องการผูกบัญชีของ social network เข้ากับบางเว็บ ด้วยเหตุผลต่าง ๆ นานา ระบบสมาชิกจึงยังจำเป็นอยู่&lt;br /&gt;
&lt;br /&gt;
ตอนแรกขอพูดถึงการสมัครสมาชิกก่อน แล้วตอนต่อไปจะว่ากันเรื่องการ log in และ log out เพราะถ้ายังไม่สมัครสมาชิกก่อน ก็ log in ไม่ได้...&lt;br /&gt;
&lt;br /&gt;
ในระบบสมาชิก สิ่งที่จำเป็นจริง ๆ มีอยู่ 2 อันคือ &lt;strong&gt;ชื่อผู้ใช้&lt;/strong&gt; และ &lt;strong&gt;รหัสผ่าน&lt;/strong&gt; แต่ควรจะมี &lt;strong&gt;อีเมล&lt;/strong&gt; เพื่อใช้ในการติดต่อกับสมาชิกไว้ด้วย&lt;br /&gt;
&lt;br /&gt;
จะขอข้ามไม่พูดถึงเรื่องการสร้างฐานข้อมูล และตาราง แต่จะบอกแค่ชื่อ และโครงสร้างของตาราง นอกจากนั้น ใช้ความรู้เรื่อง &lt;a href="http://tutor0x.blogspot.com/search/label/PHP"&gt;PHP&lt;/a&gt; และ &lt;a href="http://tutor0x.blogspot.com/2012/11/php-pdo.html"&gt;PDO&lt;/a&gt; เขียนสคริปท์ PHP กันเอาเอง หรือไม่ก็ใช้เครื่องมือจัดการฐานข้อมูลอย่าง &lt;a href="http://www.phpmyadmin.net/"&gt;phpMyAdmin&lt;/a&gt; (MySQL), &lt;a href="http://phppgadmin.sourceforge.net/"&gt;phpPgAdmin&lt;/a&gt; (PostgreSQL) หรือตัวอื่น ๆ ตามแต่ละชนิดฐานข้อมูลกันตามสะดวก&lt;br /&gt;
&lt;script class="brush: sql" type="syntaxhighlighter"&gt;
-- TABLE: members
id int NOT NULL PRIMARY KEY
username varchar(255) NOT NULL
password varchar(255) NOT NULL
email varchar(255) NOT NULL
&lt;/script&gt;  เมื่อฐานข้อมูลพร้อมแล้ว ก็สร้างแบบฟอร์มสำหรับสมัครสมาชิกขึ้นมาก่อน  &lt;script class="brush: php" type="syntaxhighlighter"&gt;
&lt;form id="register" method="post" action="regis.php"&gt;
     &lt;label&gt;Username: &lt;/label&gt;
     &lt;input type="text" id="username" name="username" /&gt;

     &lt;label&gt;Password: &lt;/label&gt;
     &lt;input type="password" id="password" name="password" /&gt;

     &lt;label&gt;Confirm Password: &lt;/label&gt;
     &lt;input type="password" id="cpassword" name="cpassword" /&gt;

     &lt;label&gt;E-Mail: &lt;/label&gt;
     &lt;input type="text" id="email" name="email" /&gt;

     &lt;input type="reset" name="reset" id="reset" value="Reset" /&gt;

     &lt;input type="submit" name="register" id="register" value="Register" /&gt;
&lt;/form&gt;&lt;/script&gt;  เมื่อมีคนมาสมัครสมาชิก ข้อมูลจะถูกส่งมายัง regis.php ก็ต้องตรวจสอบค่าให้ถูกต้องเรียบร้อยก่อนว่าผู้ใช้กรอกข้อมูลครบถ้วนสมบูรณ์ดี หากผิดพลาดก็แจ้งเตือนกลับไป  &lt;script class="brush: php" type="syntaxhighlighter"&gt;
&lt;?php
// FILE: regis.php

$error = false;

$u_name = $_POST['username'];
$u_pass = $_POST['password'];
$u_cpass = $_POST['cpassword'];
$u_email = $_POST['email'];

// validate
if (strlen($u_name) &lt; 4) {
    echo 'Username too short, minimum is 4 characters';
    $error = true;
}
if (strlen($u_pass) &lt; 6) {
    echo 'Password too short, minimum is 6 characters';
    $error = true;
}
if ($u_pass != $u_cpass) {
    echo 'Password an comfirm password are different';
    $error = true;
}
if (!filter_var($u_email, FILTER_VALIDATE_EMAIL)) {
    echo 'Invalide E-Mail';
    $error = true;
}
&lt;/script&gt;

เมื่อตรวจสอบข้อมูลเรียบร้อยแล้ว หากไม่มีอะไรผิดพลาดก็เชื่อมต่อกับฐานข้อมูล และตรวจสอบว่ามีใครใช้ชื่อนี้ไปก่อนหรือยัง เพราะชื่อบัญชีห้ามซ้ำกัน
&lt;a name='more'&gt;&lt;/a&gt;
&lt;script class="brush: php" type="syntaxhighlighter"&gt;
&lt;?php
// FILE: regis.php
.
.
.

if (!$error) {
    // your database information
    $db_host = 'localhost';
    $db_name = 'tutor0x';
    $db_user = 'user0x';
    $db_pass = 'pass0x';
    
    // connect
    try {
        // You must change this if you use different database system
        $conn = new PDO("mysql:host=$db_host; dbname=$db_name", $db_user, $db_pass);
        
        $conn-&gt;exec("SET CHARACTER SET utf8");
        
        // prepare sql for checking username
        $result = $conn-&gt;prepare("SELECT COUNT(*) FROM members WHERE username='" . $u_name . "'");
        
        $result-&gt;execute();
        
        if ($result !== false) {
            if ($result-&gt;fetchColumn() &gt; 0) {
                echo 'This username already taken';
                $error = true;
            }
        }

        if (!$error) {
            // Everything fine, add register info into database
            // TODO: write insert statement
        }
        
        $conn = null;
    }
    catch (PDOException $e) {
        echo $e-&gt;getMessage();
    }
}
&lt;/script&gt;  อันนี้ใช้ความสามารถของ PDO::prepare() ในการป้องกัน SQL Injection นอกจากนี้ ถ้าต้องการตรวจสอบว่าใช้ อีเมลเดียวกันในการสมัครหรือไม่ ก็อาจจะเพิ่มการตรวจสอบเข้าไปอีกครั้งก็ได้ โดยใช้วิธีเดียวกับตอนตรวจสอบชื่อบัญชี&lt;br /&gt;
&lt;br /&gt;
หลังจากทุกอย่างเป็นปกติ ก็นำข้อมูลผู้ใช้เข้าสู่ฐานข้อมูล (เพิ่มโค้ดตรง &lt;code&gt;// TODO: ...&lt;/code&gt; บรรทัดที่ 35)  &lt;script class="brush: php" type="syntaxhighlighter"&gt;
.
.
.

if (!$error) {
    // Everyting fine, add register info into database
    
    // prepare array
    $user = array(
            'name'  =&gt; $u_name,
            'pass'  =&gt; $u_pass,
            'email' =&gt; $u_email,
            );

    $result = $conn-&gt;prepare("INSERT INTO members VALUES (null, :name, :pass, :email)");
    $result-&gt;execute($user);
    
    if ($result !== false) {
        echo 'Registration Completed.';
    }
}

.
.
.
&lt;/script&gt;  แค่นี้ระบบลงทะเบียนก็จะสมบูรณ์ แต่มันยังมีปัญหาด้านความปลอดภัยอยู่ หากมีผู้ไม่ประสงค์ดี สามารถเจาะเข้าฐานข้อมูล เขาจะได้รหัสผ่านไปใช้ได้ทันที และในกรณีที่เลวร้ายกว่า หากสมาชิกใช้ ชื่อบัญชี อีเมล และรหัสผ่านเดียวกันกับหลาย ๆ เว็บ คนร้ายก็จะเอาข้อมูลเหล่านี้ไปใช้กับเว็บอื่น ๆ ได้ด้วย ดังนั้นวิธีนี้จึงไม่เหมาะสมอย่างยิ่งอย่างยิ่งในการใช้งานจริง&lt;br /&gt;
&lt;br /&gt;
ทางออกที่ดีกว่าสำหรับเรื่องนี้ คือการเก็บ hash ของรหัสผ่าน แทนที่จะเก็บตัวรหัสผ่านตรง ๆ ซึ่ง PHP มีฟังชั่นพื้นฐานที่นิยมใช้กับรหัสผ่านอยู่ 2 ตัวคือ &lt;a href="http://php.net/manual/en/function.md5.php"&gt;md5&lt;/a&gt; และ &lt;a href="http://php.net/manual/en/function.sha1.php"&gt;sha1&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
หากต้องการใช้ sha1 ก็ให้แก้ไขค่าของ &lt;code&gt;pass&lt;/code&gt; ในอาเรย์ &lt;code&gt;$user&lt;/code&gt; เสียใหม่  &lt;script class="brush: php" type="syntaxhighlighter"&gt;
    $user = array(
            'name'  =&gt; $u_name,
            'pass'  =&gt; sha1($u_pass),
            'email' =&gt; $u_email,
            );
&lt;/script&gt;  รหัสที่เข้ามาจะถูกแปลงเป็นรหัสที่อ่านไม่ออกอย่างเช่น &lt;code&gt;7c4a8d09ca3762af61e59520943dc26494f8941b&lt;/code&gt; และเก็บเข้าฐานข้อมูล ซึ่งหากข้อมูลที่เข้ามาเหมือนกัน ค่าที่ได้จะเหมือนกันทุกครั้ง&lt;br /&gt;
&lt;br /&gt;
แม้ว่าตอนนี้รหัสผ่านจะเดาไม่ได้ด้วยตาเปล่าแล้ว แต่ปัญหาอีกอย่างคือ หากเป็นรหัสผ่านง่าย ๆ เพียงนำ hash ที่ได้ไปค้นหากับ Google เราก็อาจจะได้รหัสผ่านตัวจริงออกมาอย่างง่ายดาย&lt;br /&gt;
&lt;br /&gt;
แต่ถึงแม้จะหาจาก Google ไม่เจอ คนร้ายยังสามารถใช้วิธี brute-force เพื่อหาข้อความที่มีค่า hash ตรงกับที่ได้มาได้  หรือหากไม่เจอ ก็สามารถใช้วิธี brute-force ค้นหาข้อความที่ได้ค่า hash ตรงกับที่ได้มาได้อยู่ดี&lt;br /&gt;
&lt;br /&gt;
เพื่อเพิ่มความยุ่งยากอีกนิด จึงมีเทคนิคที่เรียกว่า salt ขึ้นมา โดยการเพิ่มข้อความต่อเข้ากับรหัสผ่าน (ไม่ว่าจะเป็นด้านหน้า ด้านหลัง หรือตรงกลาง) เพื่อให้รหัสผ่านยาวขึ้น และซับซ้อนมากขึ้น และป้องกัน rainbow table (ตาราง ฐานข้อมูล หรือเว็บบาง&lt;a href="http://md5-database.org/"&gt;เว็บ&lt;/a&gt; ที่เก็บผลของการ hash ข้อความต่าง ๆ เอาไว้ และใช้ตรวจสอบหาค่า hash โดยไม่ต้องคำนวนใหม่ทุกครั้ง &amp;mdash; &lt;em&gt;อ่านเพิ่มเติมจาก &lt;a href="https://en.wikipedia.org/wiki/Rainbow_table"&gt;wiki&lt;/a&gt;, &lt;a href="http://www.thaicert.or.th/papers/technical/2012/pp2012te0013.html"&gt;ThaiCERT&lt;/a&gt;&lt;/em&gt;) ทั้งนี้ salt ที่ใช้ควรจะมีความยาว และซับซ้อนพอสมควร&lt;br /&gt;
&lt;br /&gt;
salt มีอยู่ 2 แบบคือ salt ที่ใช้ค่าคงที่  &lt;script class="brush: php" type="syntaxhighlighter"&gt;
$user['pass'] = sha1($u_pass . 'Salt makes delicious password!');
&lt;/script&gt;  และแบบ dynamic  &lt;script class="brush: php" type="syntaxhighlighter"&gt;
$user['pass'] = sha1($u_pass . md5($u_pass));
&lt;/script&gt;  หรือรวมกัน  &lt;script class="brush: php" type="syntaxhighlighter"&gt;
$user['pass'] = sha1('NaCl' . $u_pass . md5($u_pass));
&lt;/script&gt;  แม้ว่าจะปลอดภัยขึ้น แต่หากคนร้ายสามารถคาดเดาว่าใช้ salt ค่าของ salt รวมถึงวิธีสร้าง salt ได้ถูกต้อง เขาก็ยังสามารถ brute-force เพื่อหารหัสผ่านได้อยู่ดี แต่ยังมีวิธีการ และเทคนิคอื่น ๆ เพื่อช่วยให้เว็บของเราปลอดภัยขึ้น&lt;br /&gt;
&lt;br /&gt;
หากเรียนรู้เรื่องความปลอดภัย เราจะเข้าใจว่า "ในโลกของความปลอดภัย ไม่มีอะไรปลอดภัย" แม้ว่าจะใช้เทคนิคด้านความปลอดภัยชั้นสูง หากมันคุ้มค่าที่จะเจาะข้อมูล คนร้ายก็ยอมเสียเวลา และทรัพยากร เพื่อจะเจาะมันให้ได้ แต่หากมันไม่คุ้มค่า ต่อให้ไม่มีความปลอดภัยใด ๆ ก็ไม่มีใครสนใจจะเจาะอยู่ดี (เรียนรู้จาก&lt;a href="https://www.blognone.com/node/38351#comment-510338"&gt;ความเห็น&lt;/a&gt;ของ &lt;a href="https://twitter.com/public_lewcpe"&gt;@lewcpe&lt;/a&gt; แห่ง &lt;a href="https://www.blognone.com"&gt;blognone&lt;/a&gt;)&lt;br /&gt;
&lt;br /&gt;
แต่ถึงอย่างไรก็ตาม เราควรทำให้ระบบของเราปลอดภัยระดับหนึ่ง และควรจะปรับปรุง และเพิ่มระดับความปลอดภัยขึ้นเรื่อย ๆ เมื่อมีฐานผู้ใช้มากขึ้น เพื่อไม่ให้เกิดปัญหาอย่างกรณีของ &lt;a href="http://net.tutsplus.com"&gt;Tuts+&lt;/a&gt; ที่แนะนำเกี่ยวกับ&lt;a href="http://net.tutsplus.com/tutorials/php/understanding-hash-functions-and-keeping-passwords-safe/"&gt;การเก็บรหัสผ่านอย่างปลอดภัย&lt;/a&gt; แต่กลับเก็บรหัสผ่านแบบ plain text เอาไว้ และไม่แก้ไข ทั้ง ๆ ที่รู้อยู่ว่าไม่ปลอดภัย จนกระทั่ง&lt;a href="http://notes.envato.com/general/tuts-premium-security/"&gt;โดนแฮ็ค&lt;/a&gt;...</description><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">2</thr:total></item><item><title>Haskell: ชนิดของตัวเลข</title><link>http://tutor0x.blogspot.com/2012/12/haskell_2.html</link><category>Haskell</category><author>noreply@blogger.com (nz)</author><pubDate>Sun, 2 Dec 2012 15:34:00 +0700</pubDate><guid isPermaLink="false">tag:blogger.com,1999:blog-3074227793814140422.post-1241434205602166191</guid><description>ระบบชนิดตัวแปรของ Haskell จะแตกต่างจากภาษาอื่นๆ ตรงที่แบ่งออกได้เป็น 2 ส่วน คือ&lt;br /&gt;
&lt;ol&gt;&lt;li&gt;type class ลำดับชั้นของตัวแปรที่บ่งบอกความสัมพันธ์กับฟังก์ชันต่างๆ&lt;/li&gt;
&lt;li&gt;type ชนิดของตัวแปร โดยตัวแปรชนิดนึงสามารถมีได้หลาย class&lt;/li&gt;
&lt;/ol&gt;อาจมองได้ง่ายๆ อีกอย่างว่า type คือวิธี implement ข้อมูล ส่วน type class จะเป็นตัวกำหนดความสามารถของ type นั้นๆ ครับ&lt;br /&gt;
&lt;br /&gt;
ซึ่งตัวเลขใน Haskell สามารถจัดแบ่งคร่าวๆ ได้ดังนี้&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;ตัวเลข class: &lt;code&gt;Num&lt;/code&gt;&lt;/li&gt;
&lt;ul&gt;&lt;li&gt;จำนวนเต็ม class: &lt;code&gt;Integral&lt;/code&gt;&lt;/li&gt;
&lt;ul&gt;&lt;li&gt;type: &lt;code&gt;Int&lt;/code&gt; จำนวนเต็มตาม&lt;a href="http://en.wikipedia.org/wiki/Integer_(computer_science)#Words"&gt;ขนาด word ของคอมพิวเตอร์&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;type: &lt;code&gt;Integer&lt;/code&gt; จำนวนเต็มในอุดมคติ ไม่มีขอบเขตบน/ล่าง&lt;/li&gt;
&lt;/ul&gt;&lt;li&gt;ทศนิยม class: &lt;code&gt;Floating&lt;/code&gt;, &lt;code&gt;Fractional&lt;/code&gt;&lt;/li&gt;
&lt;ul&gt;&lt;li&gt;type: &lt;code&gt;Float&lt;/code&gt; ทศนิยมแบบ &lt;a href="http://en.wikipedia.org/wiki/Single_precision"&gt;single&lt;/a&gt; ความละเอียด 9 หลัก&lt;/li&gt;
&lt;li&gt;type: &lt;code&gt;Double&lt;/code&gt; ทศนิยมแบบ &lt;a href="http://en.wikipedia.org/wiki/Double-precision_floating-point_format"&gt;double&lt;/a&gt; ความละเอียด 18 หลัก&lt;/li&gt;
&lt;/ul&gt;&lt;/ul&gt;&lt;/ul&gt;&lt;br /&gt;
&lt;hr /&gt;&lt;br /&gt;
และเราสามารถตรวจสอบ type ได้โดยใช้ command &lt;code&gt;:t&lt;/code&gt; (หรือเต็มๆ คือ &lt;code&gt;:type&lt;/code&gt;) แล้วตามด้วยตัวแปร เช่น&lt;br /&gt;
&lt;br /&gt;
&lt;script class="brush: python" type="syntaxhighlighter"&gt;
ghci&gt; :t 42
42 :: Num a =&gt; a
ghci&gt; :t 1.0
1.0 :: Fractional a =&gt; a
ghci&gt; :t 42 + 1.0
42 + 1.0 :: Fractional a =&gt; a
&lt;/script&gt;&lt;br /&gt;
type class พร้อมตัวแปรที่ใช้แสดงแทนนั้น จะถูกบอกไว้ก่อนเครื่องหมาย &lt;code&gt;=&amp;gt;&lt;/code&gt; ส่วนอีกด้านจะบอก type ของตัวแปร ซึ่งในกรณีที่เราไม่ได้เจาะจง type ลงไปเช่นนี้ Haskell จะจัดมันไว้ใน type class ที่ใหญ่ที่สุดไว้ก่อน เพื่อที่ว่าถ้าดำเนินการกับ type class ที่เป็นลูกหลานของมันจะยังให้ผลลัพท์ที่ถูกต้อง&lt;br /&gt;
&lt;br /&gt;
ส่วนการประกาศ type แบบเจาะจงก็ทำได้โดยใส่ 2 colon แล้วตามด้วย type ไว้ข้างหลังตัวแปรนั้น&lt;br /&gt;
&lt;br /&gt;
&lt;script class="brush: python" type="syntaxhighlighter"&gt;
ghci&gt; let answer = 42 :: Float
ghci&gt; :t answer
answer :: Float
&lt;/script&gt;&lt;br /&gt;
จะเห็นว่าคราวนี้ไม่มีการบอก type class กับ &lt;code&gt;=&amp;gt;&lt;/code&gt; แล้ว เพราะเรารู้ type ที่แน่นอนของมันนั่นเอง&lt;br /&gt;
&lt;br /&gt;
อย่างที่บอกไว้แต่ต้น การดำเนินการข้าม type หรือ type class ที่ไม่เกี่ยวข้องกันนั้น ไม่สามารถทำได้ใน Haskell เช่น error ในตัวอย่างนี้&lt;br /&gt;
&lt;br /&gt;
&lt;script class="brush: plain" type="syntaxhighlighter"&gt;
ghci&gt; (1 :: Int) + (1 :: Integer)

&lt;interactive&gt;: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)

&lt;/script&gt;&lt;br /&gt;
เลขทั้งสองตัวนั้นก็ต่างอยู่ใน type class &lt;code&gt;Integral&lt;/code&gt; เหมือนกัน แต่เมื่อถูกกำหนดโดย type ต่างกัน จะทำให้ไม่สามารถนำมาบวกกันได้&lt;br /&gt;
&lt;br /&gt;
ทางออกคือ&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;จำนวนเต็มสามารถใช้ฟังก์ชัน &lt;code&gt;fromIntegral&lt;/code&gt; เพื่อเปลี่ยน type class กลับไปเป็น &lt;code&gt;Num&lt;/code&gt; ก่อนเอาไปคำนวณต่อ&lt;/li&gt;
&lt;li&gt;ทศนิยมใช้ฟังก์ชัน &lt;code&gt;truncate&lt;/code&gt; (ปัดทิ้ง), &lt;code&gt;floor&lt;/code&gt; (ปัดลง), &lt;code&gt;ceiling&lt;/code&gt; (ปัดขึ้น), &lt;code&gt;round&lt;/code&gt; (ปัดครึ่ง) เพื่อเปลี่ยน type class เป็น &lt;code&gt;Integral&lt;/code&gt; ได้&lt;/li&gt;
&lt;/ul&gt;</description><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total></item><item><title>Haskell: ใช้เป็นเครื่องคิดเลข</title><link>http://tutor0x.blogspot.com/2012/12/haskell.html</link><category>Haskell</category><author>noreply@blogger.com (nz)</author><pubDate>Sat, 1 Dec 2012 22:24:00 +0700</pubDate><guid isPermaLink="false">tag:blogger.com,1999:blog-3074227793814140422.post-5730746848240515346</guid><description>ตัวเลขใน Haskell ก็เหมือนภาษาอื่น ที่แบ่งออกหลักๆ เป็นจำนวนเต็มกับทศนิยม&lt;br /&gt;
&lt;br /&gt;
โดยการประกาศทศนิยม จะมีข้อบังคับว่า หน้าและหลังจุดทศนิยมต้องมีตัวเลขเสมอ (แม้จะเป็น 0 ก็ตาม)&lt;br /&gt;
&lt;script class="brush: python" type="syntaxhighlighter"&gt;
ghci&gt; 1
ghci&gt; 2.0
ghci&gt; 0.5
&lt;/script&gt;&lt;br /&gt;
&lt;hr /&gt;&lt;br /&gt;
การดำเนินการบวกลบคูณหาร ก็ใช้ operator &lt;code&gt;+&lt;/code&gt;, &lt;code&gt;-&lt;/code&gt;, &lt;code&gt;*&lt;/code&gt;, &lt;code&gt;/&lt;/code&gt; เช่นเดียวกับภาษาอื่นๆ&lt;br /&gt;
&lt;script class="brush: python" type="syntaxhighlighter"&gt;
ghci&gt; 1.0 + 2.0
3.0
ghci&gt; 2 - 0.5
1.5
ghci&gt; 6 * 7
42
ghci&gt; 10 / 2
5.0
&lt;/script&gt;&lt;br /&gt;
สังเกตว่าการหารจะให้ผลลัพท์เป็นทศนิยมเสมอ ส่วนการหารแบบไม่เก็บเศษ (ให้ผลลัพท์เป็นจำนวนเต็ม) จะใช้ฟังก์ชัน &lt;code&gt;div&lt;/code&gt; แทน&lt;br /&gt;
&lt;script class="brush: python" type="syntaxhighlighter"&gt;
ghci&gt; div 10 2
5
&lt;/script&gt;&lt;br /&gt;
จะเห็นว่า การเรียกฟังก์ชั่นใน Haskell ไม่ใช้วงเล็บล้อมรอบตัวแปรเหมือนภาษาอื่นๆ&lt;br /&gt;
&lt;br /&gt;
ส่วนถ้ารู้สึกไม่สะดวกที่จะเขียนอย่างข้างบน ก็สามารถใช้ grave accent (&lt;code&gt;`&lt;/code&gt;) ล้อมรอบชื่อฟังก์ชัน เพื่อให้มันทำงานเป็น infix แบบเดียวกับ operator พวกนั้นได้ (จะใช้ได้ก็ต่อเมื่อเป็นฟังก์ชันที่รับตัวแปร 2 ตัวเท่านั้น)&lt;br /&gt;
&lt;script class="brush: python" type="syntaxhighlighter"&gt;
ghci&gt; 10 `div` 2
5
&lt;/script&gt;&lt;br /&gt;
ข้อแตกต่างอีกอย่างจาก &lt;code&gt;/&lt;/code&gt; คือ &lt;code&gt;div&lt;/code&gt; จะรับตัวแปรทั้ง 2 ตัวเป็นจำนวนเต็มเท่านั้น&lt;br /&gt;
&lt;br /&gt;
และเมื่อต้องการหารเก็บเศษ ก็ใช้ฟังก์ชัน &lt;code&gt;mod&lt;/code&gt; นั่นเอง&lt;br /&gt;
&lt;script class="brush: python" type="syntaxhighlighter"&gt;
ghci&gt; 10 `mod` 2
0
&lt;/script&gt;&lt;br /&gt;
&lt;hr /&gt;&lt;br /&gt;
ส่วนการยกกำลังก็เช่นเดียวกับการหาร คือมี operator 2 แบบให้เลือกใช้&lt;br /&gt;
&lt;script class="brush: python" type="syntaxhighlighter"&gt;
ghci&gt; 2 ^ 10
1024
ghci&gt; 2 ** 10
1024.0
&lt;/script&gt;&lt;br /&gt;
ท้ายนี้ ถึงแม้ว่า Haskell จะไม่ใช้วงเล็บเพื่อส่งตัวแปรให้ฟังก์ชัน แต่วงเล็บก็สามารถใช้เพื่อบอกกลุ่มของตัวแปรได้เช่นเดียวกับภาษาทั่วไปครับ&lt;br /&gt;
&lt;script class="brush: python" type="syntaxhighlighter"&gt;
ghci&gt; (3 + 7 `div` 4) ^ 5
1024
&lt;/script&gt;&lt;br /&gt;
หรือถ้ากลัวงง ก็สามารถประกาศค่าเหล่านั้นเป็นตัวแปร (ค่าคงที่) ได้โดยใช้คำสั่ง &lt;code&gt;let&lt;/code&gt;&lt;br /&gt;
&lt;script class="brush: python" type="syntaxhighlighter"&gt;
ghci&gt; let x = 7 `div` 4
ghci&gt; let y = 3 + x
ghci&gt; y ^ 5
1024
&lt;/script&gt;&lt;br /&gt;
ย้ำอีกครั้งว่า Haskell เป็นภาษา purely functional เพราะฉะนั้นจะไม่มี operator สำหรับเปลี่ยนแปลงค่าของตัวแปรเหล่านั้นนะครับ&lt;br /&gt;
</description><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total></item><item><title>Haskell: เกร็ดน่ารู้ก่อนเริ่มใช้งาน</title><link>http://tutor0x.blogspot.com/2012/11/haskell_30.html</link><category>Haskell</category><author>noreply@blogger.com (nz)</author><pubDate>Fri, 30 Nov 2012 16:42:00 +0700</pubDate><guid isPermaLink="false">tag:blogger.com,1999:blog-3074227793814140422.post-3445488427222611578</guid><description>จากตอนที่ผ่านมา จะเห็นว่าแบบ interactive นั้นไม่ต้องเขียน &lt;code&gt;main = do&lt;/code&gt; ขึ้นต้น นั่นเป็นเพราะว่าเมื่อเริ่ม &lt;code&gt;ghci&lt;/code&gt; เราจะเข้ามาอยู่ด้านในของ &lt;code&gt;main&lt;/code&gt; ที่ว่านั้นทันที ซึ่งการเขียน code ภายใน &lt;code&gt;main&lt;/code&gt; จะมีกฏที่ต่างออกไปเล็กน้อยด้วย&lt;br /&gt;
&lt;br /&gt;
ความสะดวกอย่างอื่นๆ ของตัว interactive&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;แสดงผลลัพท์จากคำสั่งที่พิมพ์เข้าไปทันที (&lt;a href="http://en.wikipedia.org/wiki/Read%E2%80%93eval%E2%80%93print_loop"&gt;read-eval-print-loop&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;ทำ keyword completion ด้วย tab&lt;/li&gt;
&lt;li&gt;macro สำหรับการ debug โดยใช้เครื่องหมาย colon ตามด้วย command (เช่น &lt;code&gt;:q&lt;/code&gt; ที่ได้เจอไปแล้ว)&lt;/li&gt;
&lt;/ul&gt;อย่างไรก็ตาม ตัว interactive นั้นไม่รองรับการเขียนหลายบรรทัดเป็นค่าเริ่มต้น ถ้าต้องการเขียนหลายบรรทัด ให้เริ่มด้วย &lt;code&gt;:{&lt;/code&gt; และขึ้นบรรทัดใหม่ แล้วค่อยเริ่มส่วน code เรียบร้อยแล้วจบด้วยบรรทัดที่มีแต่ &lt;code&gt;:}&lt;/code&gt; ครับ&lt;br /&gt;
&lt;br /&gt;
อนึ่ง เครื่องหมายหน้าบรรทัดที่บอกว่ากำลังอยู่ใน interactive จะเขียนว่า &lt;code&gt;Prelude&amp;gt;&lt;/code&gt; ซึ่งต่อไปเมื่อทำการ load module เยอะๆ แล้ว ข้อความตรงนี้จะเปลี่ยนไปบอกว่า load อะไรมาแล้วบ้าง (ซึ่งอาจจะยาวมาก) ดังนั้น ที่นี้จะใช้แค่ &lt;code&gt;ghci&amp;gt;&lt;/code&gt; แทน (สามารถ set ให้เป็นข้อความนี้ได้ด้วย &lt;code&gt;:set prompt "ghci&amp;gt;"&lt;/code&gt; ครับ)&lt;br /&gt;
&lt;br /&gt;
&lt;hr /&gt;&lt;br /&gt;
ส่วนการเขียนโปรแกรมเก็บเป็นไฟล์นั้น นอกจากจะใช้ &lt;code&gt;ghc&lt;/code&gt; เพื่อ compile เป็น binary code ออกมาทดสอบแล้ว ยังมี &lt;code&gt;runhaskell&lt;/code&gt; ที่อ่านไฟล์แล้วรันให้ทันทีโดยไม่สร้างไฟล์พวก &lt;code&gt;.o&lt;/code&gt;, &lt;code&gt;.hi&lt;/code&gt; หรือตัว binary code ให้ แน่นอนว่ามันจะทำงานได้ช้ากว่าแบบ binary code เพราะไม่โดน optimize ด้วยตัว compiler และยังต้องแปลใหม่ทุกครั้งที่เรียกใช้ครับ&lt;br /&gt;
&lt;br /&gt;
ก็เลือกใช้ &lt;code&gt;ghci&lt;/code&gt;, &lt;code&gt;ghc&lt;/code&gt; และ &lt;code&gt;runhaskell&lt;/code&gt; กันตามความเหมาะสมนะครับ&lt;br /&gt;
&lt;br /&gt;
&lt;hr /&gt;&lt;br /&gt;
ด้านนามสกุลไฟล์นอกจาก &lt;code&gt;.hs&lt;/code&gt; แล้ว ก็มี &lt;code&gt;.lhs&lt;/code&gt; ซึ่งเป็นไฟล์ที่เน้นการเขียนโปรแกรมแบบเอกสาร แล้วแทรก code ตามจุดต่างๆ (&lt;a href="http://en.wikipedia.org/wiki/Literate_programming"&gt;literate programming&lt;/a&gt;) ตัวอย่างก็เช่น&lt;br /&gt;
&lt;br /&gt;
&lt;script class="brush: plain" type="syntaxhighlighter"&gt;
Hello World Program
===================

This program simply says "Hello, world!" then exit.

&gt; main = do
&gt;     putStrLn "Hello, world!"
&lt;/script&gt;&lt;br /&gt;
โปรแกรมนี้จะแสดงผลลัพท์เช่นเดียวกับตอนที่แล้ว อย่างไรก็ตามส่วนที่อธิบายโปรแกรมนั้น ไม่ได้ส่งผลให้เกิดความแตกต่างของ binary code แต่อย่างใด&lt;br /&gt;
&lt;br /&gt;
ส่วนการ comment source ใน Haskell แบบบรรทัดเดียวใช้ &lt;code&gt;--&lt;/code&gt; เพื่อ comment ข้อความจนจบบรรทัด และแบบหลายบรรทัดใช้ &lt;code&gt;{-&lt;/code&gt; กับ &lt;code&gt;-}&lt;/code&gt; ครอบส่วนที่ต้องการ comment&lt;br /&gt;
&lt;br /&gt;
ในที่นี้จะไม่ใช้ comment ให้ดู เนื่องจากตัว syntax highlighter ไม่ระบายสีให้ครับ :P</description><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">1</thr:total></item><item><title>Haskell: สวัสดีโลก</title><link>http://tutor0x.blogspot.com/2012/11/haskell.html</link><category>Haskell</category><author>noreply@blogger.com (nz)</author><pubDate>Thu, 29 Nov 2012 13:47:00 +0700</pubDate><guid isPermaLink="false">tag:blogger.com,1999:blog-3074227793814140422.post-6941472091872414292</guid><description>1990 มาตรฐานภาษา Haskell 1.0 ปรากฏตัว&lt;br /&gt;
1998 รวบรวมมาตรฐานภาษารุ่นก่อนๆ ได้เป็น Haskell 98&lt;br /&gt;
2003 &lt;a href="http://en.wikipedia.org/wiki/Glasgow_Haskell_Compiler"&gt;GHC&lt;/a&gt; เครื่องมือแปลภาษา Haskell ได้รับความนิยมจนเป็นมาตรฐานกลายๆ&lt;br /&gt;
2010 ตัวภาษาเดินทางมาถึงรุ่น Haskell 2010&lt;br /&gt;
&lt;br /&gt;
ชื่อภาษาตั้งเพื่อเป็นเกียรติแก่ &lt;a href="http://en.wikipedia.org/wiki/Haskell_Curry"&gt;Haskell Curry&lt;/a&gt; นักคณิตศาสตร์ผู้บุกเบิก &lt;a href="http://en.wikipedia.org/wiki/Combinatory_logic#Summary_of_the_lambda_calculus"&gt;combinatory logic&lt;/a&gt; ครับ&lt;br /&gt;
&lt;br /&gt;
&lt;hr /&gt;&lt;br /&gt;
Haskell เป็นภาษา purely functional ซึ่งทำให้เราไม่สามารถเปลี่ยนค่าตัวแปรหลังจากที่ประกาศมันได้ ส่งผลให้การคำนวณซ้ำแบบ loop ต้องเปลี่ยนไปเขียนในรูป recursion หรือ list comprehension แทน ซึ่งจะช่วยลด side effect อย่างการแชร์ตัวแปรจากที่เดียวกันได้ นอกจากนี้ตัวภาษายังเป็นแบบ lazy evaluation คือจะทำการคำนวณให้เมื่อขอดูผลลัพท์เท่านั้นครับ&lt;br /&gt;
&lt;br /&gt;
โหลดโปรแกรม &lt;code&gt;haskell-platform&lt;/code&gt; มาติดตั้งได้จาก&lt;a href="http://hackage.haskell.org/platform/"&gt;ที่นี่&lt;/a&gt; รองรับทั้ง Windows, Mac และ Linux (สำหรับ Debian ติดตั้งจาก &lt;code&gt;apt-get&lt;/code&gt; ได้ด้วย) หรือจะไป&lt;a href="http://tryhaskell.org/"&gt;ทดลองเล่น intepreter ขนาดย่อมผ่านหน้าเว็บ&lt;/a&gt;ก่อนก็ได้ &lt;br /&gt;
&lt;br /&gt;
&lt;hr /&gt;&lt;br /&gt;
Haskell นั้นมาพร้อมกับ compiler และ interpreter ในตัว ซึ่งทั้งสองแบบนี้จะมีการทำงานแตกต่างกันเล็กน้อย ว่าแล้วก็มาลอง hello กัน โดยเริ่มที่แบบ interpreter ก่อน โดยพิมพ์&lt;br /&gt;
&lt;script class="brush: plain" type="syntaxhighlighter"&gt;
$ ghci
&lt;/script&gt;&lt;br /&gt;
เพื่อเข้าสู่ Haskell interpreter ซึ่งมีข้อความต้อนรับดังนี้&lt;br /&gt;
&lt;script class="brush: plain" type="syntaxhighlighter"&gt;
GHCi, version 7.4.1: http://www.haskell.org/ghc/  :? for help
Loading package ghc-prim ... linking ... done.
Loading package integer-gmp ... linking ... done.
Loading package base ... linking ... done.
Prelude&amp;gt; _
&lt;/script&gt;&lt;br /&gt;
พิมพ์&lt;br /&gt;
&lt;script class="brush: python" type="syntaxhighlighter"&gt;
Prelude&amp;gt; putStrLn "Hello, world!"
&lt;/script&gt;&lt;br /&gt;
ก็จะพบกับข้อความทักทาย เรียบร้อยแล้วออกโปรแกรมโดยพิมพ์ &lt;code&gt;:q [Enter]&lt;/code&gt; หรือป้อน EOF ก็ได้&lt;br /&gt;
&lt;br /&gt;
ส่วนแบบที่ต้อง compile สร้างไฟล์ใหม่ที่มีข้อความดังนี้&lt;br /&gt;
&lt;script class="brush: python" type="syntaxhighlighter"&gt;
main = do
    putStrLn "Hello, world!"
&lt;/script&gt;&lt;br /&gt;
เซฟเป็นไฟล์ &lt;code&gt;hello.hs&lt;/code&gt; แล้วสั่ง&lt;br /&gt;
&lt;script class="brush: plain" type="syntaxhighlighter"&gt;
$ ghc hello.hs
&lt;/script&gt;&lt;br /&gt;
จะได้ไฟล์ &lt;code&gt;hello&lt;/code&gt; มา (ต่างจาก compiler อย่าง &lt;code&gt;gcc&lt;/code&gt; ที่จะได้ไฟล์ &lt;code&gt;a.out&lt;/code&gt;) และเรียกโปรแกรมโดย&lt;br /&gt;
&lt;script class="brush: plain" type="syntaxhighlighter"&gt;
$ ./hello
Hello, world!
&lt;/script&gt;&lt;br /&gt;
ก็เป็นอันเสร็จพิธี</description><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total></item><item><title>PHP: PDO กับฐานข้อมูล</title><link>http://tutor0x.blogspot.com/2012/11/php-pdo.html</link><category>PHP</category><category>SQL</category><author>noreply@blogger.com (Unknown)</author><pubDate>Thu, 22 Nov 2012 18:33:00 +0700</pubDate><guid isPermaLink="false">tag:blogger.com,1999:blog-3074227793814140422.post-1053570207912672820</guid><description>ในการใช้ PHP ทำงานร่วมกับฐานข้อมูล จำเป็นต้องรู้ภาษา &lt;a href="http://tutor0x.blogspot.com/search/label/SQL"&gt;SQL&lt;/a&gt; เสียก่อน และต้องรู้ด้วยว่า ฐานข้อมูลที่ต้องทำงานด้วยนั้นเป็นระบบไหน เพราะ PHP มี&lt;a href="http://www.php.net/manual/en/refs.database.vendors.php"&gt;คำสั่งเฉพาะสำหรับฐานข้อมูลแต่ละระบบ&lt;/a&gt;แยกกันอยู่&lt;br /&gt;
&lt;br /&gt;
แต่เมื่อมีเทคโนโลยีมากขึ้นระบบฐานข้อมูลมีความหลากหลายมากขึ้น ความคล่องตัวในการย้ายฐานข้อมูลจากระบบหนึ่งไปยังอีกระบบหนึ่งก็ยุ่งยากขึ้น ทาง PHP จึงสร้าง extension ชื่อ &lt;a href="http://www.php.net/manual/en/book.pdo.php"&gt;PDO&lt;/a&gt; (PHP Data Objects) ขึ้นมาเพื่อเป็นตัวกลางในการจัดการฐานข้อมูล โดยโปรแกรมเมอร์&lt;em&gt;แทบ&lt;/em&gt;ไม่ต้องสนใจว่า ระบบฐานข้อมูลที่จะทำงานร่วมกันเป็นแบบไหน&lt;br /&gt;
&lt;br /&gt;
การเชื่อมต่อกับระบบฐานข้อมูลผ่าน PDO ก็ให้สร้างออปเจ็กของคลาสขึ้นมา
&lt;script class="brush: php" type="syntaxhighlighter"&gt;
&lt;?php

// prepare database connection variables
$db_host = 'localhost';
$db_name = 'tutor0x';
$db_user = 'user0x';
$db_pass = 'pass0x';

// connect
try {
    // If you change db server system, change this too!
    $conn = new PDO("mysql:host=$db_host; dbname=$db_name", $db_user, $db_pass);
    echo "Connected to database";
}
catch (PDOException $e) {
    echo $e-&gt;getMessage();
}
&lt;/script&gt;

ตัวอย่างข้างต้นใช้ MySQL แต่ถ้าต้องการเปลี่ยนเป็นอย่างอื่นก็แก้ไขบรรทัดที่ 12 ให้เป็นระบบฐานข้อมูลนั้น ๆ หากไม่มีการใช้คำสั่ง SQL ที่จำเพาะต่อระบบฐานข้อมูลนั้น ๆ ก็จะไม่ต้องแก้ไขโค้ดในส่วนอื่น ๆ อีก

&lt;script class="brush: php" type="syntaxhighlighter"&gt;
&lt;?php

// PostgreSQL
$conn = new PDO("pgsql:host=$db_host port=5432 dbname=$db_name", $db_user, $db_pass);

// Oracle
$conn = new PDO("OCI:dbname=$db_name;charset=UTF-8", $db_user, $db_pass);

// ODBC with MS Access database
$conn = new PDO("odbc:Driver={Microsoft Access Driver (*.mdb)};Dbq="C:\database.mdb;Uid=Admin");

// SQLite
$conn = new PDO("sqlite:/path/to/database.sqlite");
&lt;/script&gt;

ส่วนการปิดการเชื่อมต่อนั้น ตามหลักแล้ว PHP จะปิดการเชื่อมต่อให้โดยอัตโนมัติเมื่อจบสคริปท์ แต่หากต้องการสั่งเองก็ใช้
&lt;script class="brush: php" type="syntaxhighlighter"&gt;
&lt;?php

$conn = null;
&lt;/script&gt;

เมื่อเชื่อมต่อกับฐานข้อมูลได้แล้ว ก็สามารถใช้คำสั่ง SQL จัดการกับฐานข้อมูลได้ 2 วิธี คือ
&lt;ul&gt;
&lt;li&gt;สั่งโดยตรงผ่านฟังชั่น &lt;code&gt;exec()&lt;/code&gt; และ &lt;code&gt;query()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;ใช้ฟังชั่น &lt;code&gt;prepare()&lt;/code&gt; และ &lt;code&gt;excute()&lt;/code&gt;
&lt;/ul&gt;
&lt;a name='more'&gt;&lt;/a&gt;
&lt;code&gt;exec()&lt;/code&gt; จะใช้กับคำสั่ง SQL ที่ไม่คืนข้อมูลกลับมา อย่าง &lt;code&gt;INSERT, UPDATE, DELETE&lt;/code&gt; เป็นต้น เพราะตัวฟังชั่นจะคืนแต่จำนวนแถวที่ได้รับผลกระทบกลับมา หรือหากทำงานไม่สำเร็จมันจะคืนค่า &lt;code&gt;false&lt;/code&gt; กลับมา
&lt;script class="brush: php" type="syntaxhighlighter"&gt;
&lt;?php

try {
    // connect to database
    $conn = new PDO("mysql:host=$db_host; dbname=$db_name", $db_user, $db_pass);
    echo "Connected to database \n";

    // prevent unreadable characters in many languages
    $conn-&gt;exec("SET CHARACTER SET utf8");

    // add data into database
    $count = $conn-&gt;exec("INSERT INTO application VALUES (null, 'Opera', 'Browser', 'Opera Software ASA', 1994)");

    // display result
    echo 'Rows add: ' . $count . "\n";

    // close connection
    $conn = null;
}
catch (PDOException $e) {
    echo $e-&gt;getMessage();
}
&lt;/script&gt;
หากต้องการข้อมูลกลับมาแสดง หรือประมวลผลให้ใช้ &lt;code&gt;query&lt;/code&gt; แทน เวลาจะใช้ก็ใช้ &lt;code&gt;foreach&lt;/code&gt; ดึงออกมา
&lt;script class="brush: php" type="syntaxhighlighter"&gt;
&lt;?php

// get data
$result = $conn-&gt;query("SELECT name,year FROM application");

// display it
if ($result !== false) {
    echo 'There is ' . $result-&gt;rowCount() . " application(s) in database.\n";

    foreach($result as $row) {
        echo '- ' . $row['name'] . ' was released on ' . $row['year'] . "\n";
    }
}
&lt;/script&gt;
แต่ข้อมูลนี้ไม่ใช่อาเรย์ แต่เป็นออปเจ็กของคลาส PDOStatement โดยมีกระบวนการภายในของคลาสคอยจัดการข้อมูลให้ หากไม่ได้กำหนดพารามิเตอร์เพิ่มเติมให้กับฟังชั่น &lt;code&gt;query()&lt;/code&gt; ค่าที่ได้จะเป็นทั้ง associative array ที่ใช้ชื่อคอลัมภ์เป็นคีย์ และ numberic array ที่ใช้ตัวเลข (เริ่มจาก 0) เป็น index (ซึ่งภายในมันก็คือตัวเดียวกันนั่นแหละ)&lt;br /&gt;
&lt;br /&gt;
นอกจากใช้ &lt;code&gt;foreach&lt;/code&gt; แล้ว สามารถใช้ &lt;code&gt;while()&lt;/code&gt; ร่วมกับ &lt;code&gt;fetch()&lt;/code&gt; ซึ่งสามารถกำหนดรูปแบบของข้อมูลเพิ่มเติมเข้าไปได้หากต้องการ
&lt;script class="brush: php" type="syntaxhighlighter"&gt;
&lt;?php

// get data
$result = $conn-&gt;query("SELECT name,year FROM application");

// display it
if ($result !== false) {
    echo 'There is ' . $result-&gt;rowCount() . " application(s) in database.\n";

    while($row = $result-&gt;fetch()) {
        echo '- ' . $row['name'] . ' was released on ' . $row['year'] . "\n";
    }
}
&lt;/script&gt;
ฟังชั่น &lt;code&gt;exec()&lt;/code&gt; และ &lt;code&gt;query()&lt;/code&gt; นั้นมีความเสี่ยงด้านความปลอดภัยอยู่ เราจำเป็นต้องใช้คำสั่ง &lt;code&gt;quote()&lt;/code&gt; กับคำสั่ง SQL ด้วยตัวเอง เพื่อป้องกัน SQL Injection หรืออีกวิธีหนึ่งคือ ฟังชั่น &lt;code&gt;prepare()&lt;/code&gt; ร่วมกับ &lt;code&gt;execute()&lt;/code&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;code&gt;prepare()&lt;/code&gt; จะเป็นการเตรียมคำสั่ง SQL ให้พร้อมก่อนที่จะคิวรี่ไปยังฐานข้อมูล
&lt;script class="brush: php" type="syntaxhighlighter"&gt;
&lt;?php

// prepare and query (direct)
$result = $conn-&gt;prepare("SELECT * FROM application WHERE category='Browser'");
$result-&gt;execute();

// display it
if ($result !== false) {
    echo $result-&gt;rowCount() . " application(s) in Browser category.\n";

    while($row = $result-&gt;fetch()) {
        echo '- ' . $row['name'] . ' was released on ' . $row['year'] . "\n";
    }
}
&lt;/script&gt;
นอกจากนี้ &lt;code&gt;prepare()&lt;/code&gt; ยังรองรับการผูก (bind) ระหว่างอาเรย์เข้ากับคำสั่ง SQL ซึ่งช่วยให้การคิวรี่ข้อมูลมาก ๆ จากฐานข้อมูลทำได้สะดวกขึ้น ซึ่งจะมี 2 แบบ คือ&lt;br /&gt;
&lt;br /&gt;
&lt;strong&gt;แบบไม่ตั้งชื่อ&lt;/strong&gt; จะใช้เครื่องหมาย ? วางไว้ในตำแหน่งที่จะแทรกข้อมูล โดย PHP จะนำข้อมูลไปใส่ให้ตามลำดับ
&lt;script class="brush: php" type="syntaxhighlighter"&gt;
&lt;?php

// category that I want to show
$cat = {'OS', 'Office Suite'};

$result = $conn-&gt;prepare("SELECT * FROM application WHERE category=? OR category=?");
$result-&gt;execute($cat);

if ($result !== false) {
    echo 'Found ' . $result-&gt;rowCount() . " application(s).\n";

    while($row = $result-&gt;fetch()) {
        echo '- ' . $row['name'] . ' was released on ' . $row['year'] . "\n";
    }
}
&lt;/script&gt;
&lt;strong&gt;อีกแบบคือมีการตั้งชื่อให้กับตำแหน่งที่จะวาง&lt;/strong&gt; โดยใช้ : นำหน้าชื่อ แล้วใช้ associative array ที่มีคีย์เป็นชื่อเดียวกัน
&lt;script class="brush: php" type="syntaxhighlighter"&gt;
&lt;?php

$term = array(
    'cat'   =&gt; 'Browser',
    'year'  =&gt; 2000,
);

// prepare query
$result = $conn-&gt;prepare("SELECT * FROM application WHERE category=:cat AND year&gt;:year");

// bind statement and query it
$result-&gt;execute($term);

if ($result !== false) {
    echo 'Found ' . $result-&gt;rowCount() . " application(s).\n";

    while($row = $result-&gt;fetch()) {
        echo '- ' . $row['name'] . ' was released on ' . $row['year'] . "\n";
    }
}
&lt;/script&gt;
เมื่อจะเปลี่ยนแปลงค่าก็แก้ไขค่าในอาเรย์ แล้วสั่ง &lt;code&gt;execute()&lt;/code&gt; ใหม่ได้ทันที
&lt;script class="brush: php" type="syntaxhighlighter"&gt;
&lt;?php

function display_data($result) {
    if ($result !== false) {
        echo 'Found ' . $result-&gt;rowCount() . " application(s).\n";

        while($row = $result-&gt;fetch()) {
            echo '- ' . $row['name'] . ' was released on ' . $row['year'] . "\n";
        }
    }
}

$term = array(
    'cat'   =&gt; 'Browser',
    'year'  =&gt; 2000,
);

// prepare query
$query = $conn-&gt;prepare("SELECT * FROM application WHERE category=:cat AND year&gt;:year");

// bind statement and query it
$query-&gt;execute($term);
display_data($query);

// change bind data
$term = array(
    'cat'   =&gt; 'Graphic Editor',
    'year'  =&gt; 1991,
);

// bind with new data and query it
$query-&gt;execute($term);
display_data($query);

&lt;/script&gt;

แม้ว่า PDO จะมีข้อดีเรื่องการทำงานกับระบบฐานข้อมูลได้หลากหลาย แต่หากต้องการรีดประสิทธิภาพ และความเร็วในการจัดการฐานข้อมูลให้มากที่สุด รวมทั้งใช้คำสั่งพิเศษที่มีเฉพาะระบบฐานข้อมูลนั้น ๆ การใช้คำสั่งสำหรับฐานข้อมูลแต่ละตัวเป็นสิ่งจำเป็น ซึ่งก็แลกมาด้วยการแก้ไขโค้ดจำนวนมาก เมื่อต้องการเปลี่ยนฐานข้อมูลเป็นระบบอื่น หรือต้องการให้โปรแกรมที่เขียนขึ้นรองรับฐานข้อมูลที่หลากหลายขึ้น อันนี้ก็ต้องช่างใจกันเอาเอง&lt;br /&gt;
&lt;br /&gt;
แต่หากใช้ framework ต่าง ๆ ในการทำงาน แนะนำให้ใช้คำสั่งเฉพาะที่ framework นั้น ๆ มีให้ แทนที่จะเข้าถึงฐานข้อมูลโดยตรง เพราะ framework จะคอยจัดการเชื่อมต่อ และเตรียมข้อมูลที่คิวรี่ได้มาให้โดยอัตโนมัติ ซึ่งง่าย สะดวก และปลอดภัยกว่า
</description><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">3</thr:total></item><item><title>SQL: สร้าง เพิ่ม ลบ อัพเดทข้อมูลในฐานข้อมูล</title><link>http://tutor0x.blogspot.com/2012/11/sql.html</link><category>SQL</category><author>noreply@blogger.com (Unknown)</author><pubDate>Mon, 12 Nov 2012 20:07:00 +0700</pubDate><guid isPermaLink="false">tag:blogger.com,1999:blog-3074227793814140422.post-6478921404204774830</guid><description>&lt;style&gt;
.entry-content table { width: 95%; border-collapse: collapse; margin: 20px auto; }
.entry-content table tr:nth-child(odd) { background-color: #eee; }
.entry-content table tr:nth-child(even) { background-color: transparent; }
.entry-content table th { text-alight: left; }
.entry-content table th { background-color: #e0e0e0; }
.entry-content table th,
.entry-content table td { padding: 5px; border: 1px solid #ccc; }
&lt;/style&gt;
ใน&lt;a href="http://tutor0x.blogspot.com/2012/11/sql-select.html"&gt;ตอนก่อน&lt;/a&gt; พูดถึงการแสดงข้อมูล และค้นหาข้อมูลตามที่ต้องการ คราวนี้มาดูวิธีการสร้างฐานข้อมูล ตาราง และการเพิ่ม ลบ แก้ไขเปลี่ยนแปลงข้อมูลของตารางกันกันบ้าง&lt;br /&gt;
&lt;br /&gt;
การสร้างฐานข้อมูลนั้นจะใช้คำสั่ง &lt;code&gt;CREATE&lt;/code&gt; ซึ่งผู้ใช้จะสร้างฐานข้อมูลได้หรือไม่นั้น ขึ้นอยู่กับว่า บัญชีนั้นมีสิทธิ์ที่จะทำได้หรือไม่ด้วย ซึ่งในหลาย ๆ โฮสต์ จะอนุญาตให้สร้างฐานข้อมูลผ่านทาง back-end แทนที่จะสร้างโดยตรงผ่านทางคำสั่ง SQL
&lt;script class="brush: sql" type="syntaxhighlighter"&gt;
CREATE DATABASE knowledge_db
&lt;/script&gt;
เราก็จะได้ฐานข้อมูลเปล่า ๆ มาอันนึง ซึ่งจำเป็นต้องสร้างตารางขึ้นมาเพื่อเก็บข้อมูลเพิ่มเติมโดยใช้คำสั่ง &lt;code&gt;CREATE&lt;/code&gt; เช่นเดียวกัน โดยต้องระบุ ชื่อคอลัมภ์พร้อมคุณลักษณะต่าง ๆ อย่างเช่น ชนิดของข้อมูลในคอลัมภ์นั้น ๆ ด้วย&lt;br /&gt;
&lt;br /&gt;
นอกจากนี้ ยังต้องคำนึงด้วยว่าระบบฐานข้อมูลที่ใช้อยู่เป็นตัวไหน เพราะคำสั่งนี้บางส่วนในบางระบบจะใช้ไม่เหมือนกัน (อย่างเช่นการกำหนด primary key และ การเพิ่มค่าอัตโนมัติในตัวอย่าง)
&lt;script class="brush: sql" type="syntaxhighlighter"&gt;
-- MySQL: define primary key in last argument
CREATE TABLE application
(
     id int NOT NULL,
     name varchar(255) NOT NULL,
     category varchar(255),
     developer varchar(255),
     year int,
     PRIMARY KEY (id)
)
&lt;/script&gt;
&lt;script class="brush: sql" type="syntaxhighlighter"&gt;
-- SQL Server/Oracle/MS Access: define primary key as column attribute
CREATE TABLE application
(
     id int NOT NULL PRIMARY KEY,
     name varchar(255) NOT NULL,
     category varchar(255),
     developer varchar(255),
     year int,
     PRIMARY KEY (id)
)
&lt;/script&gt;
&lt;script class="brush: sql" type="syntaxhighlighter"&gt;
-- PostgreSQL: use integer instead of int
-- and if that column is auto increment use serial instead
-- or add DEFAULT value to nextval('serial')
CREATE TABLE application
(
     id serial PRIMARY KEY,
     -- or use: id integer PRIMARY KEY DEFAULT nextval('serial'),
     name varchar(255) NOT NULL,
     category varchar(255),
     developer varchar(255),
     year integer
)
&lt;/script&gt;
ตอนนี้ก็จะมีตาราง application เปล่า ๆ ขึ้นมาอันหนึ่ง
&lt;table&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;th&gt;id&lt;/th&gt;&lt;th&gt;name&lt;/th&gt;&lt;th&gt;category&lt;/th&gt;&lt;th&gt;developer&lt;/th&gt;&lt;th&gt;year&lt;/th&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
การเพิ่มข้อมูล (แถว) เข้าตารางจะใช้คำสั่ง &lt;code&gt;INSERT INTO&lt;/code&gt;
&lt;script class="brush: sql" type="syntaxhighlighter"&gt;
INSERT INTO application
VALUES (null, 'Windows', 'OS', 'Mocrosoft', 1985)
&lt;/script&gt;
ในที่นี้คอลัมภ์ id จะเพิ่มโดยอัตโนมัติ (auto_increment) ถ้าส่งค่า &lt;code&gt;null&lt;/code&gt; ไประบบฐานข้อมูลจะใส่ค่าถัดไปให้โดยอัตโนมัติ และถ้าต้องการเพิ่มข้อมูลที่ละหลาย ๆ แถวก็สามารถใส่ค่าของ &lt;code&gt;VALUES&lt;/code&gt; ลงไปหลาย ๆ ชุดได้เช่นกัน
&lt;script class="brush: sql" type="syntaxhighlighter"&gt;
INSERT INTO application
VALUES (null, 'OS X', 'OS', 'Apple Inc.', 2001),
VALUES (null, 'Microsoft Office', 'Office Suite', 'Microsoft', 1990),
VALUES (null, 'Libre Office', 'Office Suite', 'The Document Foundation', 2011),
VALUES (null, 'Adobe Photoshop', 'Graphic Editor', 'Adobe', 1990),
VALUES (null, 'GIMP', 'Graphic Editor', 'The GIMP Development Team', 1996),
VALUES (null, 'Firefox', 'Browser', 'Mozilla', 2004)
&lt;/script&gt;
ผลที่ได้จะเป็น
&lt;table&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;th&gt;id&lt;/th&gt;&lt;th&gt;name&lt;/th&gt;&lt;th&gt;category&lt;/th&gt;&lt;th&gt;developer&lt;/th&gt;&lt;th&gt;year&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;Windows&lt;/td&gt;&lt;td&gt;OS&lt;/td&gt;&lt;td&gt;Microsoft&lt;/td&gt;&lt;td&gt;1985&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;OS X&lt;/td&gt;&lt;td&gt;OS&lt;/td&gt;&lt;td&gt;Apple Inc.&lt;/td&gt;&lt;td&gt;2001&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;3&lt;/td&gt;&lt;td&gt;Microsoft Office&lt;/td&gt;&lt;td&gt;Office Suite&lt;/td&gt;&lt;td&gt;Microsoft&lt;/td&gt;&lt;td&gt;1990&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;4&lt;/td&gt;&lt;td&gt;Libre Office&lt;/td&gt;&lt;td&gt;Office Suite&lt;/td&gt;&lt;td&gt;The Document Foundation&lt;/td&gt;&lt;td&gt;2011&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;5&lt;/td&gt;&lt;td&gt;Adobe Photoshop&lt;/td&gt;&lt;td&gt;Graphic Editor&lt;/td&gt;&lt;td&gt;Adobe&lt;/td&gt;&lt;td&gt;1990&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;6&lt;/td&gt;&lt;td&gt;GIMP&lt;/td&gt;&lt;td&gt;Graphic Editor&lt;/td&gt;&lt;td&gt;The GIMP Development Team&lt;/td&gt;&lt;td&gt;1996&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;7&lt;/td&gt;&lt;td&gt;Firefox&lt;/td&gt;&lt;td&gt;Browser&lt;/td&gt;&lt;td&gt;Mozilla&lt;/td&gt;&lt;td&gt;2004&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
ถ้าตารางนั้นมีข้อมูลเริ่มต้นอยู่ หรือไม่จำเป็นต้องใส่ค่าลงไปได้ สามารถที่จะระบุเฉพาะคอลัมภ์ที่ต้องการใส่ข้อมูลลงไปได้เช่นเดียวกัน
&lt;script class="brush: sql" type="syntaxhighlighter"&gt;
INSERT INTO application (name, year)
VALUES ('Chromium', 2008)
&lt;/script&gt;
ผลที่ได้จะเป็น
&lt;table&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;th&gt;id&lt;/th&gt;&lt;th&gt;name&lt;/th&gt;&lt;th&gt;category&lt;/th&gt;&lt;th&gt;developer&lt;/th&gt;&lt;th&gt;year&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;Windows&lt;/td&gt;&lt;td&gt;OS&lt;/td&gt;&lt;td&gt;Microsoft&lt;/td&gt;&lt;td&gt;1985&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;OS X&lt;/td&gt;&lt;td&gt;OS&lt;/td&gt;&lt;td&gt;Apple Inc.&lt;/td&gt;&lt;td&gt;2001&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;3&lt;/td&gt;&lt;td&gt;Microsoft Office&lt;/td&gt;&lt;td&gt;Office Suite&lt;/td&gt;&lt;td&gt;Microsoft&lt;/td&gt;&lt;td&gt;1990&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;4&lt;/td&gt;&lt;td&gt;Libre Office&lt;/td&gt;&lt;td&gt;Office Suite&lt;/td&gt;&lt;td&gt;The Document Foundation&lt;/td&gt;&lt;td&gt;2011&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;5&lt;/td&gt;&lt;td&gt;Adobe Photoshop&lt;/td&gt;&lt;td&gt;Graphic Editor&lt;/td&gt;&lt;td&gt;Adobe&lt;/td&gt;&lt;td&gt;1990&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;6&lt;/td&gt;&lt;td&gt;GIMP&lt;/td&gt;&lt;td&gt;Graphic Editor&lt;/td&gt;&lt;td&gt;The GIMP Development Team&lt;/td&gt;&lt;td&gt;1996&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;7&lt;/td&gt;&lt;td&gt;Firefox&lt;/td&gt;&lt;td&gt;Browser&lt;/td&gt;&lt;td&gt;Mozilla&lt;/td&gt;&lt;td&gt;2004&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;8&lt;/td&gt;&lt;td&gt;Chromium&lt;/td&gt;&lt;td&gt;&amp;nbsp;&lt;/td&gt;&lt;td&gt;&amp;nbsp;&lt;/td&gt;&lt;td&gt;2008&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
ส่วนการแก้ไขข้อมูลนั้นจะใช้ &lt;code&gt;UPDATE&lt;/code&gt;
&lt;script class="brush: sql" type="syntaxhighlighter"&gt;
UPDATE application
SET name='Google Chrome', category='Browser', developer='Google Inc.'
WHERE name='Chromium'
&lt;/script&gt;
ผลที่ได้จะเป็น
&lt;table&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;th&gt;id&lt;/th&gt;&lt;th&gt;name&lt;/th&gt;&lt;th&gt;category&lt;/th&gt;&lt;th&gt;developer&lt;/th&gt;&lt;th&gt;year&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;Windows&lt;/td&gt;&lt;td&gt;OS&lt;/td&gt;&lt;td&gt;Microsoft&lt;/td&gt;&lt;td&gt;1985&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;OS X&lt;/td&gt;&lt;td&gt;OS&lt;/td&gt;&lt;td&gt;Apple Inc.&lt;/td&gt;&lt;td&gt;2001&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;3&lt;/td&gt;&lt;td&gt;Microsoft Office&lt;/td&gt;&lt;td&gt;Office Suite&lt;/td&gt;&lt;td&gt;Microsoft&lt;/td&gt;&lt;td&gt;1990&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;4&lt;/td&gt;&lt;td&gt;Libre Office&lt;/td&gt;&lt;td&gt;Office Suite&lt;/td&gt;&lt;td&gt;The Document Foundation&lt;/td&gt;&lt;td&gt;2011&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;5&lt;/td&gt;&lt;td&gt;Adobe Photoshop&lt;/td&gt;&lt;td&gt;Graphic Editor&lt;/td&gt;&lt;td&gt;Adobe&lt;/td&gt;&lt;td&gt;1990&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;6&lt;/td&gt;&lt;td&gt;GIMP&lt;/td&gt;&lt;td&gt;Graphic Editor&lt;/td&gt;&lt;td&gt;The GIMP Development Team&lt;/td&gt;&lt;td&gt;1996&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;7&lt;/td&gt;&lt;td&gt;Firefox&lt;/td&gt;&lt;td&gt;Browser&lt;/td&gt;&lt;td&gt;Mozilla&lt;/td&gt;&lt;td&gt;2004&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;8&lt;/td&gt;&lt;td&gt;Google Chrome&lt;/td&gt;&lt;td&gt;Browser&lt;/td&gt;&lt;td&gt;Google Inc.&lt;/td&gt;&lt;td&gt;2008&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
สิ่งที่ควรจำให้ขึ้นใจคือ จะแก้ไขข้อมูลต้องมี &lt;code&gt;WHERE&lt;/code&gt; เสมอ ไม่เช่นนั้นจะเป็นการแก้ไขข้อมูลทั้งตาราง! และควรจะใช้เงื่อนไขของ &lt;code&gt;WHERE&lt;/code&gt; อย่างรอบคอบ เพื่อไม่ให้ข้อมูลที่ไม่เกี่ยวข้องได้รับผลกระทบ&lt;br /&gt;
&lt;br /&gt;
ส่วนการลบข้อมูลก็จะใช้ &lt;code&gt;DELETE&lt;/code&gt; ซึ่งจำเป็นต้องมี &lt;code&gt;WHERE&lt;/code&gt; เช่นกัน และที่สำคัญคือถ้าใช้ &lt;code&gt;WHERE&lt;/code&gt; ไม่รอบคอบ หรือไม่ใช้ ข้อมูลอาจจะหายไปทั้งตารางได้เช่นกัน&lt;br /&gt;
&lt;script class="brush: sql" type="syntaxhighlighter"&gt;
DELETE FROM application
WHERE category='Office Suite'
&lt;/script&gt;
&lt;table&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;th&gt;id&lt;/th&gt;&lt;th&gt;name&lt;/th&gt;&lt;th&gt;category&lt;/th&gt;&lt;th&gt;developer&lt;/th&gt;&lt;th&gt;year&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;Windows&lt;/td&gt;&lt;td&gt;OS&lt;/td&gt;&lt;td&gt;Microsoft&lt;/td&gt;&lt;td&gt;1985&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;OS X&lt;/td&gt;&lt;td&gt;OS&lt;/td&gt;&lt;td&gt;Apple Inc.&lt;/td&gt;&lt;td&gt;2001&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;5&lt;/td&gt;&lt;td&gt;Adobe Photoshop&lt;/td&gt;&lt;td&gt;Graphic Editor&lt;/td&gt;&lt;td&gt;Adobe&lt;/td&gt;&lt;td&gt;1990&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;6&lt;/td&gt;&lt;td&gt;GIMP&lt;/td&gt;&lt;td&gt;Graphic Editor&lt;/td&gt;&lt;td&gt;The GIMP Development Team&lt;/td&gt;&lt;td&gt;1996&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;7&lt;/td&gt;&lt;td&gt;Firefox&lt;/td&gt;&lt;td&gt;Browser&lt;/td&gt;&lt;td&gt;Mozilla&lt;/td&gt;&lt;td&gt;2004&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;8&lt;/td&gt;&lt;td&gt;Google Chrome&lt;/td&gt;&lt;td&gt;Browser&lt;/td&gt;&lt;td&gt;Google Inc.&lt;/td&gt;&lt;td&gt;2008&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
แม้ว่าจะใช้ &lt;code&gt;DELETE&lt;/code&gt; ลบข้อมูลทั้งตารางทิ้งไป แต่โครงสร้างตาราง ค่า index (ที่ใช้ในการค้นหาข้อมูล) รวมถึงค่าคุณลักษณะ (attribute) ต่าง ๆ ของตารางยังคงอยู่ ไม่ได้ถูกลบไปด้วย
&lt;script class="brush: sql" type="syntaxhighlighter"&gt;
DELETE FROM application
-- or add * for more meaningful 
DELETE * FROM application
&lt;/script&gt;
ตามด้วย
&lt;script class="brush: sql" type="syntaxhighlighter"&gt;
INSERT INTO application
VALUES (null, 'Internet Explorer', 'Browser', 'Microsoft', 1995)
&lt;/script&gt;
ผลจะเป็น
&lt;table&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;th&gt;id&lt;/th&gt;&lt;th&gt;name&lt;/th&gt;&lt;th&gt;category&lt;/th&gt;&lt;th&gt;developer&lt;/th&gt;&lt;th&gt;year&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;9&lt;/td&gt;&lt;td&gt;Internet Explorer&lt;/td&gt;&lt;td&gt;OS&lt;/td&gt;&lt;td&gt;Microsoft&lt;/td&gt;&lt;td&gt;1995&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
แต่หากต้องการจะลบข้อมูลในตารางทิ้งจริง ๆ แนะนำให้ใช้ &lt;code&gt;TRUNCATE&lt;/code&gt; เพราะมันรวดเร็วกว่า และใช้ทรัพยากรน้อยกว่า
&lt;script class="brush: sql" type="syntaxhighlighter"&gt;
TRUNCATE TABLE application
&lt;/script&gt;
หากจะลบตารางทั้งตารางทิ้งจะใช้คำสั่ง &lt;code&gt;DROP&lt;/code&gt;
&lt;script class="brush: sql" type="syntaxhighlighter"&gt;
DROP TABLE application
&lt;/script&gt;
ตาราง application ทั้งตารางรวมทั้งโครงสร้างจะหายไปจากฐานข้อมูล ถ้าจะใช้ตารางนี้อีก ต้องสร้างตารางขึ้นมาใหม่เสียก่อน&lt;br /&gt;
&lt;br /&gt;
นอกจากลบตารางทิ้งแล้ว &lt;code&gt;DROP&lt;/code&gt; ยังสามารถลบฐานข้อมูลทั้งฐานข้อมูลทิ้งได้เช่นกัน (ทั้งนี้ขึ้นอยู่กับสิทธิ์ในการเข้าถึงฐานข้อมูลของบัญชีผู้ใช้อันนั้น ๆ ด้วย ว่าสามารถทำได้ถึงขั้นไหน)
&lt;script class="brush: sql" type="syntaxhighlighter"&gt;
DROP DATABASE knowledge_db
&lt;/script&gt;
</description><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total></item><item><title>SQL: ดึงข้อมูลจากฐานข้อมูลด้วย SELECT</title><link>http://tutor0x.blogspot.com/2012/11/sql-select.html</link><category>SQL</category><author>noreply@blogger.com (Unknown)</author><pubDate>Mon, 5 Nov 2012 21:44:00 +0700</pubDate><guid isPermaLink="false">tag:blogger.com,1999:blog-3074227793814140422.post-50612705366559928</guid><description>&lt;style&gt;
.entry-content table { width: 95%; border-collapse: collapse; margin: 20px auto; }
.entry-content table tr:nth-child(odd) { background-color: #eee; }
.entry-content table tr:nth-child(even) { background-color: transparent; }
.entry-content table th { text-alight: left; }
.entry-content table th { background-color: #e0e0e0; }
.entry-content table th,
.entry-content table td { padding: 5px; border: 1px solid #ccc; }
&lt;/style&gt;
&lt;strong&gt;SQL&lt;/strong&gt; (&lt;strong&gt;S&lt;/strong&gt;tructured &lt;strong&gt;Q&lt;/strong&gt;uery &lt;strong&gt;L&lt;/strong&gt;anguage - ภาษาสอบถามเชิงโครงสร้าง) เป็นภาษาสำหรับจัดการฐานข้อมูลที่นิยมใช้กันมากในปัจจุบัน&lt;br /&gt;
&lt;br /&gt;
SQL พัฒนาที่ IBM โดย Donald D. Chamberlin และ Raymond F. Boyce ในปี ค.ศ. 1970 โดยมีแนวคิดบางส่วนมาจาก Edgar F. Codd เพื่อใช้กับระบบฐานข้อมูล System R&lt;br /&gt;
&lt;br /&gt;
เดิม SQL จะใช้ชื่อว่า SEQUEL (&lt;strong&gt;S&lt;/strong&gt;tructured &lt;strong&gt;E&lt;/strong&gt;nglish &lt;strong&gt;Que&lt;/strong&gt;ry &lt;strong&gt;L&lt;/strong&gt;anguage) แต่ดันมีปัญหาเรื่องเครื่องหมายการค้า เลยเปลี่ยนชื่อเป็น SQL ซึ่งอ่านได้ทั้ง &lt;em&gt;เอส-คิว-แอล&lt;/em&gt;, &lt;em&gt;ซี-เควล&lt;/em&gt; และ &lt;em&gt;ซี-ควล&lt;/em&gt; ตามชอบใจ&lt;br /&gt;
&lt;br /&gt;
ระบบฐานข้อมูลส่วนใหญ่ ไม่ว่าจะเป็น MySQL, PostgreSQL, SQL Server, Access, Oracle, DB2 หรือ SQLite ก็ใช้ SQL ในการจัดการข้อมูลทั้งสิ้น&lt;br /&gt;
&lt;br /&gt;
แต่... แม้ว่าระบบฐานข้อมูลเหล่านี้จะใช้ SQL ในการจัดการเหมือนกัน แต่รายละเอียดบางคำสั่งย่อย ๆ บางคำสั่งอาจจะแตกต่างกัน หากผลที่ได้ไม่ได้ออกมาตามต้องการ ให้คิดถึงจุดนี้ด้วย&lt;br /&gt;
&lt;br /&gt;
สำหรับข้อมูลที่ใช้จะใช้ข้อมูลตามนี้ ขอตั้งชื่อตารางว่า application&lt;br /&gt;

&lt;table&gt;&lt;tbody&gt;

&lt;tr&gt;&lt;th&gt;id&lt;/th&gt;&lt;th&gt;name&lt;/th&gt;&lt;th&gt;category&lt;/th&gt;&lt;th&gt;developer&lt;/th&gt;&lt;th&gt;year&lt;/th&gt;&lt;/tr&gt;

&lt;tr&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;Windows&lt;/td&gt;&lt;td&gt;OS&lt;/td&gt;&lt;td&gt;Microsoft&lt;/td&gt;&lt;td&gt;1985&lt;/td&gt;&lt;/tr&gt;

&lt;tr&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;OS X&lt;/td&gt;&lt;td&gt;OS&lt;/td&gt;&lt;td&gt;Apple Inc.&lt;/td&gt;&lt;td&gt;2001&lt;/td&gt;&lt;/tr&gt;

&lt;tr&gt;&lt;td&gt;3&lt;/td&gt;&lt;td&gt;Microsoft Office&lt;/td&gt;&lt;td&gt;Office Suite&lt;/td&gt;&lt;td&gt;Microsoft&lt;/td&gt;&lt;td&gt;1990&lt;/td&gt;&lt;/tr&gt;

&lt;tr&gt;&lt;td&gt;4&lt;/td&gt;&lt;td&gt;Libre Office&lt;/td&gt;&lt;td&gt;Office Suite&lt;/td&gt;&lt;td&gt;The Document Foundation&lt;/td&gt;&lt;td&gt;2011&lt;/td&gt;&lt;/tr&gt;

&lt;tr&gt;&lt;td&gt;5&lt;/td&gt;&lt;td&gt;Adobe Photoshop&lt;/td&gt;&lt;td&gt;Graphic Editor&lt;/td&gt;&lt;td&gt;Adobe&lt;/td&gt;&lt;td&gt;1990&lt;/td&gt;&lt;/tr&gt;

&lt;tr&gt;&lt;td&gt;6&lt;/td&gt;&lt;td&gt;GIMP&lt;/td&gt;&lt;td&gt;Graphic Editor&lt;/td&gt;&lt;td&gt;The GIMP Development Team&lt;/td&gt;&lt;td&gt;1996&lt;/td&gt;&lt;/tr&gt;

&lt;/tbody&gt;&lt;/table&gt;

การนำข้อมูลมาแสดงจะใช้ &lt;code&gt;SELECT ... FROM ...&lt;/code&gt; เป็นหลัก โดยอาจจะกำหนดเงื่อนไขผ่านทาง &lt;code&gt;WHERE&lt;/code&gt; (ที่จริงแล้วคำสั่ง SQL จะใช้ตัวพิมพ์เล็ก หรือตัวพิมพ์ใหญ่ก็ให้ผลเหมือนกัน เพียงแต่ใช้ตัวพิมพ์ใหญ่จะอ่านได้เข้าใจง่ายกว่า)

&lt;script class="brush: sql" type="syntaxhighlighter"&gt;
SELECT *
FROM application
&lt;/script&gt;

ผลที่ได้จะเหมือนกับตารางด้านบน คือ เอาข้อมูลทุกอย่างมาแสดง

&lt;script class="brush: sql" type="syntaxhighlighter"&gt;
SELECT name,year
FROM application
&lt;/script&gt;

อันนี้เลือกเอาจะเฉพาะคอลัมภ์ name กับ year มาแสดง

&lt;table&gt;&lt;tbody&gt;

&lt;tr&gt;&lt;th&gt;name&lt;/th&gt;&lt;th&gt;year&lt;/th&gt;&lt;/tr&gt;

&lt;tr&gt;&lt;td&gt;Windows&lt;/td&gt;&lt;td&gt;1985&lt;/td&gt;&lt;/tr&gt;

&lt;tr&gt;&lt;td&gt;OS X&lt;/td&gt;&lt;td&gt;2001&lt;/td&gt;&lt;/tr&gt;

&lt;tr&gt;&lt;td&gt;Microsoft Office&lt;/td&gt;&lt;td&gt;1990&lt;/td&gt;&lt;/tr&gt;

&lt;tr&gt;&lt;td&gt;Libre Office&lt;/td&gt;&lt;td&gt;2011&lt;/td&gt;&lt;/tr&gt;

&lt;tr&gt;&lt;td&gt;Adobe Photoshop&lt;/td&gt;&lt;td&gt;1990&lt;/td&gt;&lt;/tr&gt;

&lt;tr&gt;&lt;td&gt;GIMP&lt;/td&gt;&lt;td&gt;1996&lt;/td&gt;&lt;/tr&gt;

&lt;/tbody&gt;&lt;/table&gt;

&lt;script class="brush: sql" type="syntaxhighlighter"&gt;
SELECT DISTINCT category
FROM application
&lt;/script&gt;

อันนี้จะแสดงข้อมูลที่ไม่ซ้ำกันเท่านั้น ที่ซ้ำตัดทิ้งไป อาจะใช้หาว่า ลูกค้าของบริษัทเป็นคนจังหวัดใดบ้าง เป็นต้น

&lt;table&gt;&lt;tbody&gt;

&lt;tr&gt;&lt;th&gt;category&lt;/th&gt;&lt;/tr&gt;

&lt;tr&gt;&lt;td&gt;OS&lt;/td&gt;&lt;/tr&gt;

&lt;tr&gt;&lt;td&gt;Office Suite&lt;/td&gt;&lt;/tr&gt;

&lt;tr&gt;&lt;td&gt;Graphic Editor&lt;/td&gt;&lt;/tr&gt;

&lt;/tbody&gt;&lt;/table&gt;

แต่ถ้าหากจะกำหนดเงื่อนไขว่าเอาข้อมูลที่มีอย่างนั้นอย่างนี้จะต้องใช้ &lt;code&gt;WHERE&lt;/code&gt; เข้าช่วย โดยใช้การเปรียบเทียบทั่ว ๆ ไป รวมทั้ง &lt;code&gt;BETWEEN&lt;/code&gt; (ระหว่างค่า 2 ค่า) &lt;code&gt;LIKE&lt;/code&gt; (ค้นหาโดยใช้ pattern) และ &lt;code&gt;IN&lt;/code&gt; (ข้อมูลในคอลัมภ์เป็นค่าใดค่าหนึ่งในนี้)&lt;br /&gt;
&lt;br /&gt;
&lt;strong&gt;หมายเหตุ&lt;/strong&gt;: สำหรับการเปรียบเทียบ &lt;em&gt;ไม่เท่ากับ&lt;/em&gt; ระบบฐานข้อมูลบางตัวใช้ &lt;code&gt;&lt;&gt;&lt;/code&gt; แต่บางตัวใช้ &lt;code&gt;!=&lt;/code&gt;

&lt;script class="brush: sql" type="syntaxhighlighter"&gt;
SELECT *
FROM application
WHERE year &gt;= 2000
&lt;/script&gt;

ผลที่ได้คือ จะแสดงเฉพาะแอพที่เปิดตัวตั้งแต่ปี 2000 ขึ้นไป

&lt;table&gt;&lt;tbody&gt;

&lt;tr&gt;&lt;th&gt;id&lt;/th&gt;&lt;th&gt;name&lt;/th&gt;&lt;th&gt;category&lt;/th&gt;&lt;th&gt;developer&lt;/th&gt;&lt;th&gt;year&lt;/th&gt;&lt;/tr&gt;

&lt;tr&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;OS X&lt;/td&gt;&lt;td&gt;OS&lt;/td&gt;&lt;td&gt;Apple Inc.&lt;/td&gt;&lt;td&gt;2001&lt;/td&gt;&lt;/tr&gt;

&lt;tr&gt;&lt;td&gt;4&lt;/td&gt;&lt;td&gt;Libre Office&lt;/td&gt;&lt;td&gt;Office Suite&lt;/td&gt;&lt;td&gt;The Document Foundation&lt;/td&gt;&lt;td&gt;2011&lt;/td&gt;&lt;/tr&gt;

&lt;/tbody&gt;&lt;/table&gt;

หากจะให้ค้นหาข้อมูลจาก 2 คอลัมภ์ จะต้องใช้ &lt;code&gt;AND&lt;/code&gt; (และ) หรือ &lt;code&gt;OR&lt;/code&gt; (หรือ) เพิ่มต่อจาก &lt;code&gt;WHERE&lt;/code&gt;

&lt;script class="brush: sql" type="syntaxhighlighter"&gt;
SELECT *
FROM application
WHERE year &lt; 2000
AND category = 'OS'
&lt;/script&gt;

&lt;strong&gt;หมายเหตุ&lt;/strong&gt;: ถ้าสังเกต จะเห็นว่า การเปรียบเทียบ &lt;em&gt;เท่ากับ&lt;/em&gt; ใน SQL จะ&lt;em&gt;ใช้เครื่องหมายเท่ากับเพียงอันเดียว&lt;/em&gt; แทนที่จะเป็นสองอันแบบหลาย ๆ ภาษา

ผลที่ได้คือ แสดงข้อมูลจะเฉพาะที่ปีต่ำกว่า 2000 และอยู่ในหมวด OS เท่านั้น

&lt;table&gt;&lt;tbody&gt;

&lt;tr&gt;&lt;th&gt;id&lt;/th&gt;&lt;th&gt;name&lt;/th&gt;&lt;th&gt;category&lt;/th&gt;&lt;th&gt;developer&lt;/th&gt;&lt;th&gt;year&lt;/th&gt;&lt;/tr&gt;

&lt;tr&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;Windows&lt;/td&gt;&lt;td&gt;OS&lt;/td&gt;&lt;td&gt;Microsoft&lt;/td&gt;&lt;td&gt;1985&lt;/td&gt;&lt;/tr&gt;

&lt;/tbody&gt;&lt;/table&gt;

หากพบว่า ข้อมูลที่อยู่ในฐานข้อมูลเรียงไม่ถูกใจ สามารถสั่งเรียงข้อมูลใหม่ได้โดยผ่าน ORDER BY

&lt;script class="brush: sql" type="syntaxhighlighter"&gt;
SELECT name,category,developer,year
FROM application
ORDER BY year ASC
&lt;/script&gt;

ผลที่ได้คือ ข้อมูลที่ได้จะเรียงตามปีจากน้อยไปหามาก (&lt;code&gt;ASC&lt;/code&gt;) แต่ถ้าจะให้เรียงจากมากไปหาน้อยจะใช้ &lt;code&gt;DESC&lt;/code&gt;

&lt;table&gt;&lt;tbody&gt;

&lt;tr&gt;&lt;th&gt;name&lt;/th&gt;&lt;th&gt;category&lt;/th&gt;&lt;th&gt;developer&lt;/th&gt;&lt;th&gt;year&lt;/th&gt;&lt;/tr&gt;

&lt;tr&gt;&lt;td&gt;Windows&lt;/td&gt;&lt;td&gt;OS&lt;/td&gt;&lt;td&gt;Microsoft&lt;/td&gt;&lt;td&gt;1985&lt;/td&gt;&lt;/tr&gt;

&lt;tr&gt;&lt;td&gt;Microsoft Office&lt;/td&gt;&lt;td&gt;Office Suite&lt;/td&gt;&lt;td&gt;Microsoft&lt;/td&gt;&lt;td&gt;1990&lt;/td&gt;&lt;/tr&gt;

&lt;tr&gt;&lt;td&gt;Adobe Photoshop&lt;/td&gt;&lt;td&gt;Graphic Editor&lt;/td&gt;&lt;td&gt;Adobe&lt;/td&gt;&lt;td&gt;1990&lt;/td&gt;&lt;/tr&gt;

&lt;tr&gt;&lt;td&gt;GIMP&lt;/td&gt;&lt;td&gt;Graphic Editor&lt;/td&gt;&lt;td&gt;The GIMP Development Team&lt;/td&gt;&lt;td&gt;1996&lt;/td&gt;&lt;/tr&gt;

&lt;tr&gt;&lt;td&gt;OS X&lt;/td&gt;&lt;td&gt;OS&lt;/td&gt;&lt;td&gt;Apple Inc.&lt;/td&gt;&lt;td&gt;2001&lt;/td&gt;&lt;/tr&gt;

&lt;tr&gt;&lt;td&gt;Libre Office&lt;/td&gt;&lt;td&gt;Office Suite&lt;/td&gt;&lt;td&gt;The Document Foundation&lt;/td&gt;&lt;td&gt;2011&lt;/td&gt;&lt;/tr&gt;

&lt;/tbody&gt;&lt;/table&gt;

สำหรับข้อมูลในฐานข้อมูลนั้นจะยังคงเรียงอยู่เหมือนเดิม คำสั่งนี้ใช้เฉพาะการดึงข้อมูลมาแสดงเท่านั้น ถ้าลองสั่ง &lt;code&gt;SELECT * FROM application&lt;/code&gt; ดู ผลจะได้เหมือนกับตาราางแรกสุด&lt;br /&gt;
&lt;br /&gt;
ถ้าสังเกตดูภาษา SQL จะอ่านเข้าใจง่าย และคล้ายภาษาอังกฤษมาก</description><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">2</thr:total></item><item><title>let's code: แก้โจทย์คณิตศาสตร์กับ Project Euler</title><link>http://tutor0x.blogspot.com/2012/09/lets-code-project-euler.html</link><category>Let's Code</category><author>noreply@blogger.com (nz)</author><pubDate>Thu, 20 Sep 2012 22:38:00 +0700</pubDate><guid isPermaLink="false">tag:blogger.com,1999:blog-3074227793814140422.post-1473780951975899696</guid><description>&lt;a href="http://projecteuler.net/"&gt;Project Euler&lt;/a&gt; คือสถานที่ฝึกปรือฝีมือการแก้โจทย์ปัญหาอีกที่หนึ่ง โดยโจทย์ส่วนใหญ่จะเป็นโจทย์ทางคณิตศาสตร์-คอมพิวเตอร์ ทำให้งานนี้เขียนโปรแกรมเป็นอย่างเดียวไม่พอ ยังต้องงัดสารพัดเทคนิคทางคณิตศาสตร์ออกมาเพื่อให้แก้ปัญหาได้อย่างสวยงามอีกด้วย&lt;br /&gt;
&lt;br /&gt;
ถึงแม้จะไม่มีข้อกำหนดที่ชัดเจนว่าควรใช้ภาษาอะไร/เวลาประมวลผลเท่าไหร่ แต่ทางเว็บก็ได้ออกแบบโจทย์ทุกข้อไว้ให้สามารถแก้ได้ภายในเวลาที่น้อยกว่า 1 นาที (ด้วย algorithm ที่ optimize มาอย่างถูกต้อง) นอกจากนี้ผู้เล่นก็ควรจะซื่อสัตย์ต่อตัวเองด้วย เพราะโจทย์ทุกข้อจะใช้ test case เดิมไปตลอดครับ&lt;br /&gt;
&lt;br /&gt;
&lt;u&gt;&lt;b&gt;ภาษาที่ใช้ได้&lt;/b&gt;&lt;/u&gt;&lt;br /&gt;
ภาษาใดก็ได้ หรือจะทดคำตอบในกระดาษก็ยังไหว&lt;br /&gt;
&lt;br /&gt;
&lt;u&gt;&lt;b&gt;รูปแบบการตรวจคำตอบ&lt;/b&gt;&lt;/u&gt;&lt;br /&gt;
รับ test case จากหน้าเว็บมาประมวลผล แล้วส่งเฉพาะคำตอบ&lt;br /&gt;
&lt;br /&gt;
&lt;u&gt;&lt;b&gt;ตัวอย่างโจทย์&lt;/b&gt;&lt;/u&gt;&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;&lt;a href="http://projecteuler.net/problem=1"&gt;1&lt;/a&gt;: หาผลรวมของเลขจำนวนเต็มบวกทุกตัวที่ต่ำกว่า 1000 ซึ่งเลขแต่ละตัวเป็นผลคูณของ 3 หรือ 5&lt;/li&gt;
&lt;li&gt;&lt;a href="http://projecteuler.net/problem=25"&gt;25&lt;/a&gt;: จงหาลำดับของ&lt;a href="http://en.wikipedia.org/wiki/Fibonacci_number"&gt;เลขฟีโบนักชี&lt;/a&gt;ตัวแรก ที่เมื่อเขียนเป็นเลขฐานสิบแล้ว มีตัวเลขถึง 1000 หลัก&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://projecteuler.net/problem=80"&gt;80&lt;/a&gt;: สังเกตว่า &lt;code&gt;√2&lt;/code&gt; สามารถเขียนเป็นทศนิยมไม่รู้จบได้คือ &lt;code&gt;1.41421356237309504880...&lt;/code&gt; จงหาผลรวมของผลรวมของตัวเลข 100 หลักแรกในทศนิยมไม่รู้จบนี้ สำหรับรากที่สองของจำนวนเต็มบวกที่น้อยกว่า 100 ที่เป็นทศนิยมไม่รู้จบ&lt;/li&gt;
&lt;li&gt;&lt;a href="http://projecteuler.net/problem=206"&gt;206&lt;/a&gt;: จงหาจำนวนเต็มบวกเพียงหนึ่งเดียว ที่กำลังสองของมันสามารถเขียนให้อยู่ในรูป &lt;code&gt;1_2_3_4_5_6_7_8_9_0&lt;/code&gt; เมื่อ &lt;code&gt;_&lt;/code&gt; แทนตัวเลขอะไรก็ได้ 1 หลัก&lt;/li&gt;
&lt;/ul&gt;</description><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">2</thr:total></item><item><title>Python: รีดความเร็วด้วย PyPy</title><link>http://tutor0x.blogspot.com/2012/09/python-pypy.html</link><category>Python</category><author>noreply@blogger.com (nz)</author><pubDate>Tue, 4 Sep 2012 04:15:00 +0700</pubDate><guid isPermaLink="false">tag:blogger.com,1999:blog-3074227793814140422.post-8890855350026069162</guid><description>เนื่องจากตัว Python เป็นภาษาสคริปต์ เวลาสั่งทำงานโปรแกรมจะช้ากว่าภาษาที่ compile เตรียมไว้ก่อนอย่างไม่ต้องสงสัย&lt;br /&gt;
&lt;br /&gt;
ทางออกสำหรับโปรแกรมเมอร์ Python ที่ต้องการให้โปรแกรมเร็วขึ้นก็มีหลายวิธี ตั้งแต่วิเคราะห์ algorithm เพื่อทำ optimization ย้ายไปใช้ module ที่เขียนในภาษา C ไปจนถึงใช้ Python เป็นโครงต้นแบบแล้วเขียนโปรแกรมใหม่ทั้งหมดด้วยภาษาอื่นเลย&lt;br /&gt;
&lt;br /&gt;
จะเห็นว่าทุกวิธีที่ว่ามา มี cost ในการเปลี่ยนที่สูงพอควร ทั้งที่วิธีแก้ปัญหามันควรจะง่ายกว่านั้น เพี่ยงแค่ compile โปรแกรมที่เขียนด้วย Python เก็บไว้ก่อนเช่นเดียวกับภาษาอื่นๆ&lt;br /&gt;
&lt;br /&gt;
ตัวโครงการหลักของ Python ยังไม่มีความสามารถนี้ แต่ไม่ต้องเสียใจไป เพราะ&lt;a href="http://pypy.org/index.html"&gt;โครงการ PyPy&lt;/a&gt; สามารถเร่งความเร็วให้โปรแกรมที่เขียนใน Python โดยการใช้ JIT compiler เข้าช่วย แน่นอนว่าเราแทบไม่ต้องเขียน code ใหม่หมดเพื่อความเร็วนี้เลย&lt;br /&gt;
&lt;br /&gt;
สำหรับ Linux สามารถ&lt;a href="http://pypy.org/download.html"&gt;ดาวน์โหลด binary package&lt;/a&gt; มาติดตั้งเองได้ หรือจะสั่งติดตั้งผ่าน &lt;code&gt;apt-get&lt;/code&gt; ก็ได้เช่นกัน เพียงแค่เพิ่ม repository ก่อนดังนี้&lt;br /&gt;
&lt;script class="brush: shell" type="syntaxhighlighter"&gt;
$ apt-add-repository ppa:pypy/ppa
$ apt-get install pypy
&lt;/script&gt;&lt;br /&gt;
ส่วน Windows จะได้ไฟล์ .exe มาเลย ก่อนใช้ก็อย่าลืมเพิ่ม environmental path เพื่อความสะดวกนะครับ&lt;br /&gt;
&lt;br /&gt;
&lt;hr /&gt;&lt;br /&gt;
วิธีใช้งานก็เรียบง่ายตรงไปตรงมา แค่เปลี่ยนจาก&lt;br /&gt;
&lt;script class="brush: shell" type="syntaxhighlighter"&gt;
$ python script.py
&lt;/script&gt;&lt;br /&gt;
ไปเป็น&lt;br /&gt;
&lt;script class="brush: shell" type="syntaxhighlighter"&gt;
$ pypy script.py
&lt;/script&gt;&lt;br /&gt;
ก็เรียบร้อย โดย option ที่เพิ่มขึ้นมาจาก &lt;code&gt;python&lt;/code&gt; ธรรมดาได้แก่&lt;br /&gt;
&lt;script class="brush: shell" type="syntaxhighlighter"&gt;
$ pypy --jit off
&lt;/script&gt;&lt;br /&gt;
ที่จะทำการปิด JIT compiler ทิ้งไป โดย option นี้จะเหมาะกับโปรแกรมขนาดเล็กที่ไม่ได้ทำงานซ้ำๆ กันซักเท่าไหร่ครับ&lt;br /&gt;
&lt;br /&gt;
ข้อควรระวังในการใช้ PyPy คือตอนนี้มันยังทำงานได้กับสคริปต์ Python2 เท่านั้น ถ้าเขียoptionนเป็น Python3 แล้วต้องการทดสอบโปรแกรมใน PyPy ก็มีจุดแตกต่างหลักๆ ดังนี้&lt;br /&gt;
&lt;script class="brush: python" type="syntaxhighlighter"&gt;
# python2          python3
raw_input    =       input
xrange       =       range

# not exists in python2
from __future__ import print_function
from __future__ import division
&lt;/script&gt;&lt;br /&gt;
สำหรับรายละเอียดเต็มๆ ว่าอะไรที่ใช้ได้และไม่ได้บ้าง สามารถอ่านได้จาก&lt;a href="http://pypy.org/compat.html"&gt;หน้า compatibility&lt;/a&gt;</description><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total></item><item><title>Git: แก้ conflict จากการ merge</title><link>http://tutor0x.blogspot.com/2012/07/git-conflict-merge.html</link><category>Git</category><author>noreply@blogger.com (nz)</author><pubDate>Sun, 29 Jul 2012 23:09:00 +0700</pubDate><guid isPermaLink="false">tag:blogger.com,1999:blog-3074227793814140422.post-6501707836309137329</guid><description>ตอนก่อนจะเห็นว่า เราทำการ merge ได้อย่างสบายใจไร้กังวล เพราะ code ส่วนที่แก้นั้นอยู่คนละที่กันเลย แต่ถ้าแก้ code ในที่ๆ ซ้อนทับกัน จะเกิด conflict ซึ่งโปรแกรมไม่สามารถหยั่งรู้ได้ว่า เราต้องการ code ตอนสุดท้ายออกมาเป็นยังไงกันแน่ และเราต้องลงมือจัดการกับ conflict นั้นเองครับ&lt;br /&gt;
&lt;br /&gt;
ศึกษาการแก้ conflict โดยการแตก branch แรกเพื่อเพิ่มความสามารถให้โปรแกรมรับ &lt;code&gt;-v&lt;/code&gt; สำหรับบอกเวอร์ชั่นโปรแกรม&lt;br /&gt;
&lt;script class="brush: bash" type="syntaxhighlighter"&gt;
$ git checkout -b show-version
Switched to a new branch 'show-version'
&lt;/script&gt;&lt;br /&gt;
ที่ไฟล์ &lt;code&gt;hello.py&lt;/code&gt; ส่วนที่เช็ค &lt;code&gt;-h&lt;/code&gt; (แถวบรรทัดที่ 5) เพิ่ม code ให้เป็นอย่างนี้&lt;br /&gt;
&lt;script class="brush: python" type="syntaxhighlighter"&gt;
if '-h' in names:
    exit("usage: python hello.py [-h] [NAME [NAME ...]]")
elif '-v' in names:
    exit("advance hello beta")

&lt;/script&gt;&lt;br /&gt;
แล้วก็ commit&lt;br /&gt;
&lt;script class="brush: bash" type="syntaxhighlighter"&gt;
$ git commit -am 'add option -v as show version'
[show-version 02513a2] add option -v as show version
 1 file changed, 2 insertions(+)
&lt;/script&gt;&lt;br /&gt;
เรียร้อยกับ branch แรกไปแล้ว ก็มาทำ branch ที่สอง โดยเขียนให้โปรแกรมรับ &lt;code&gt;-l&lt;/code&gt; เพื่อบอกลิขสิทธิ์โปรแกรม&lt;br /&gt;
&lt;script class="brush: bash" type="syntaxhighlighter"&gt;
$ git checkout master 
Switched to branch 'master'
$ git checkout -b show-license
Switched to a new branch 'show-license'
&lt;/script&gt;&lt;br /&gt;
แก้ไฟล์ &lt;code&gt;hello.py&lt;/code&gt; ที่เดิมเลย (แค่เปลี่ยนหน้าตา code นิดหน่อย)&lt;br /&gt;
&lt;script class="brush: python" type="syntaxhighlighter"&gt;
if '-h' in names:
    exit("usage: python hello.py [-h] [NAME [NAME ...]]")
elif '-l' in names:
    exit("license under WTFPL v2.0")

&lt;/script&gt;&lt;br /&gt;
เช่นเดิม commit มันซะ&lt;br /&gt;
&lt;script class="brush: bash" type="syntaxhighlighter"&gt;
$ git commit -am 'add option -l as show license'
[show-license ec29013] add option -l as show license
 1 file changed, 2 insertions(+)
&lt;/script&gt;&lt;br /&gt;
คราวนี้กลับมาที่ master แล้วทำการ merge เหมือนตอนที่ผ่านมา&lt;br /&gt;
&lt;script class="brush: bash" type="syntaxhighlighter"&gt;
$ git checkout master 
Switched to branch 'master'
$ git merge show-version show-license 
Fast-forwarding to: show-version
Trying simple merge with show-license
Simple merge did not work, trying automatic merge.
Auto-merging hello.py
ERROR: content conflict in hello.py
fatal: merge program failed
Automatic merge failed; fix conflicts and then commit the result.
&lt;/script&gt;&lt;br /&gt;
พบว่ามีฟ้อง conflict และส่งผลให้ merge ไม่ผ่าน ตอนนี้ถ้าดูสถานะจะพบว่า&lt;br /&gt;
&lt;script class="brush: bash" type="syntaxhighlighter"&gt;
$ git status 
# On branch master
# Unmerged paths:
#   (use "git add/rm &lt;file&gt;..." as appropriate to mark resolution)
#
# both modified:      hello.py
#
no changes added to commit (use "git add" and/or "git commit -a")
&lt;/script&gt;&lt;br /&gt;
หมายเหตุว่า Git จะไม่ยอมให้ย้าย branch ถ้าหากยังมี conflict เช่นนี้อยู่ ดังนั้นมาเก็บข้อผิดพลาดนี้กัน โดยเปิดไฟล์ &lt;code&gt;hello.py&lt;/code&gt; ขึ้นมา จะเห็นดังนี้&lt;br /&gt;
&lt;script class="brush: python" type="syntaxhighlighter"&gt;
import sys

names = sys.argv[1:]

if '-h' in names:
    exit("usage: python hello.py [-h] [NAME [NAME ...]]")
&lt;&lt;&lt;&lt;&lt;&lt;&lt; .merge_file_trt1cP
elif '-v' in names:
    exit("advance hello beta")
=======
elif '-l' in names:
    exit("license under WTFPL v2.0")
&gt;&gt;&gt;&gt;&gt;&gt;&gt; .merge_file_XPZY4N

if not names:
    print("Hello, world!")

if '-s' in names:
    names.remove('-s')
    names.sort()

for name in names:
    print("Hi {}.".format(name))

&lt;/script&gt;&lt;br /&gt;
ส่วนที่เกิด conflict จะถูกคั่นด้วยบรรทัดที่ขึ้นต้นด้วยเครื่องหมาย &lt;code&gt; &lt;&lt;&lt;&lt;&lt;&lt;&lt; &lt;/code&gt;, &lt;code&gt; ======= &lt;/code&gt;, &lt;code&gt; &gt;&gt;&gt;&gt;&gt;&gt;&gt; &lt;/code&gt; ในตัวอย่างนี้ จัดการลบ 3 บรรทดนั้นทิ้งไปก็พอครับ (สำหรับงานจริง เปิดอ่านโปรแกรมแล้วจัดการเรียบเรียง code ใหม่ให้ทำงานถูกต้องนะครับ)&lt;br /&gt;
&lt;br /&gt;
ตอนนี้อาจจะทดสอบเพิ่มกันอีกเล็กน้อย เมื่อมั่นใจว่าโปรแกรมทำงานถูกต้องแล้ว ก็สั่ง commit ความเปลี่ยนแปลงนี้ครับ (ไม่ใช่สั่ง merge ไปอีกรอบนะครับ -- ตัว Git จะรู้ได้เองว่านี่เป็นการแก้ conflict ที่เกิดจากการ merge)&lt;br /&gt;
&lt;script class="brush: bash" type="syntaxhighlighter"&gt;
$ git commit -am 'manual merge show-version and show-license'
[master 388a013] manual merge show-version and show-license
&lt;/script&gt;&lt;br /&gt;
ถึงตอนนี้ถ้ายังไม่มั่นใจว่าทั้ง 2 branch นั้นถูก merge แล้วจริงหรือเปล่า สามารถดูด้วย &lt;code&gt;branch --no-merged&lt;/code&gt; ซึ่งควรจะไม่แสดงผลลัพท์ออกมา (เพราะถูก merge เรียบร้อยแล้ว) และถ้าสั่ง &lt;code&gt;branch --merged&lt;/code&gt; ก็ควรจะเห็นครบ&lt;br /&gt;
&lt;script class="brush: bash" type="syntaxhighlighter"&gt;
$ git branch --no-merged
$ git branch --merged 
* master
  show-license
  show-version
&lt;/script&gt;&lt;br /&gt;
เรียบร้อยแล้วก็ลบ branch ทั้ง 2 ทิ้งเลยครับ&lt;br /&gt;
&lt;script class="brush: bash" type="syntaxhighlighter"&gt;
$ git branch show-version show-license -d
Deleted branch show-version (was 02513a2).
Deleted branch show-license (was ec29013).
&lt;/script&gt;</description><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total></item><item><title>Git: ทำการ merge หลาย branch</title><link>http://tutor0x.blogspot.com/2012/07/git-merge-branch.html</link><category>Git</category><author>noreply@blogger.com (nz)</author><pubDate>Sat, 28 Jul 2012 22:14:00 +0700</pubDate><guid isPermaLink="false">tag:blogger.com,1999:blog-3074227793814140422.post-1417734090649764836</guid><description>ในการทำงานร่วมกันหลายคน ย่อมมี branch เกิดขึ้นมากมายแน่นอน (มันคงไม่มีประโยชน์ถ้าจะรอให้คนนึงทำงานแรกเสร็จก่อน แล้วค่อยอนุญาตให้อีกคนทำงานถัดมา) ความสามารถในการ merge หลายๆ branch ที่แตกออกมาในเวลาเดียวกันนั้น จึงเป็นสิ่งที่โปรแกรม SCM ควรทำได้อย่างเป็นเรื่องปรกติธรรมดา&lt;br /&gt;
&lt;br /&gt;
ตอนนี้จะทดสอบการ merge หลาย branch โดยเพิ่มความสามารถ 2 อย่างให้โปรเจค hello&lt;br /&gt;
&lt;br /&gt;
ความสามารถแรกคือการแสดง help ซึ่งสามารถเรียกโดยเพิ่ม &lt;code&gt;-h&lt;/code&gt; ทาง command line เช่นเดียวกับโปรแกรมทั่วๆ ไปครับ&lt;br /&gt;
&lt;script class="brush: bash" type="syntaxhighlighter"&gt;
$ git checkout -b show-help
Switched to a new branch 'show-help'
&lt;/script&gt;&lt;br /&gt;
แก้ code ในไฟล์ &lt;code&gt;hello.py&lt;/code&gt; ดังนี้&lt;br /&gt;
&lt;script class="brush: python" type="syntaxhighlighter"&gt;
import sys

names = sys.argv[1:]

if '-h' in names:
    exit("usage: python hello.py [-h] [NAME [NAME ...]]")
    
if not names:
    print("Hello, world!")

for name in names:
    print("Hi {}.".format(name))

&lt;/script&gt;&lt;br /&gt;
(ทดสอบแล้วผ่าน) ก็ commit ตามปรกติครับ&lt;br /&gt;
&lt;script class="brush: bash" type="syntaxhighlighter"&gt;
$ git commit -am 'add option -h as show help'
[show-help 052a17b] add option -h as show help
 1 file changed, 3 insertions(+)
&lt;/script&gt;&lt;br /&gt;
เรียบร้อยกับความสามารถแรกไปแล้ว ทีนี้มาเพิ่มความสามารถที่สอง โดยกลับไปแตก branch มาจากตัว master นะครับ&lt;br /&gt;
&lt;script class="brush: bash" type="syntaxhighlighter"&gt;
$ git checkout master 
Switched to branch 'master'
$ git checkout -b sort-name
Switched to a new branch 'sort-name'
&lt;/script&gt;&lt;br /&gt;
ความสามารถนี้ จะทำการเรียงลำดับชื่อที่รับเข้ามาก่อน แล้วค่อยทักทายแต่ละชื่อที่เรียงแล้วนั้น ซึ่งสามารถเรียกโดยเพิ่ม &lt;code&gt;-s&lt;/code&gt; เข้าไปตอนเรียกโปรแกรมครับ&lt;br /&gt;
&lt;script class="brush: python" type="syntaxhighlighter"&gt;
import sys

names = sys.argv[1:]

if not names:
    print("Hello, world!")

if '-s' in names:
    names.remove('-s')
    names.sort()

for name in names:
    print("Hi {}.".format(name))

&lt;/script&gt;&lt;br /&gt;
(ทดสอบกันเอง) แล้วก็ commit ครับ&lt;br /&gt;
&lt;script class="brush: bash" type="syntaxhighlighter"&gt;
$ git commit -am 'add option -s as sorted name'
[sort-name a973745] add option -s as sorted name
 1 file changed, 4 insertions(+)
&lt;/script&gt;&lt;br /&gt;
สลับกลับมาที่ master ถึงตอนนี้เราอาจจะลืมไปแล้วว่าได้ทำการเปลี่ยนแปลงอะไรไว้ที่ branch อื่นบ้าง เราสามารถสั่งให้แสดงความแตกต่างระหว่าง branch ดังนี้ครับ&lt;br /&gt;
&lt;script class="brush: bash" type="syntaxhighlighter"&gt;
$ git checkout master 
Switched to branch 'master'
$ git diff master show-help 
diff --git a/hello.py b/hello.py
index 728f301..13c71ed 100644
--- a/hello.py
+++ b/hello.py
@@ -2,6 +2,9 @@ import sys
 
 names = sys.argv[1:]
 
+if '-h' in names:
+    exit("usage: python hello.py [-h] [NAME [NAME ...]]")
+
 if not names:
     print("Hello, world!")
 
&lt;/script&gt;&lt;br /&gt;
ข้อมูล 4 บรรทัดแรกจากคำสั่ง diff จะบอกว่าทำการหาความแตกต่างระหว่าง branch ไหน ข้อมูลในบรรทัดที่ 5 (ขึ้นต้นด้วยเครื่องหมาย &lt;code&gt;@@&lt;/code&gt;) จะบอกช่วงบรรทัดที่นำมาแสดง และข้อมูลที่เหลือจะแสดงอยู่ในรูปของ patch file คือถ้ามีเครื่องหมาย &lt;code&gt;+&lt;/code&gt; หมายถึงมีข้อมูลเพิ่มขึ้นมา เครื่องหมาย &lt;code&gt;-&lt;/code&gt; คือข้อมูลที่ถูกลบทิ้งครับ&lt;br /&gt;
&lt;br /&gt;
เมื่อพร้อมแล้วก็ merge กันเลย &lt;br /&gt;
&lt;script class="brush: bash" type="syntaxhighlighter"&gt;
$ git merge show-help sort-name 
Fast-forwarding to: show-help
Trying simple merge with sort-name
Simple merge did not work, trying automatic merge.
Auto-merging hello.py
Merge made by the 'octopus' strategy.
 hello.py |    7 +++++++
 1 file changed, 7 insertions(+)
&lt;/script&gt;&lt;br /&gt;
สังเกตว่าการ merge ย่อยครั้งแรก (show-help) แม้จะเป็นการ Fast-forward เช่นเดียวกับที่ผ่านมา แต่เมื่อ merge เสร็จ จะมี code ส่วนที่ตรวจว่ามีการขอ help หรือเปล่าเพิ่มขึ้น ทำให้บรรทัดต่างๆ ใน code ส่วนที่เหลือถูกเลื่อนลงมาข้างล่างด้วย เมื่อ Git พยายามจะ merge ครั้งถัดมา (sort-name) มันจะทำการเลื่อน code ส่วนที่ต้องตรวจว่าจะ sort หรือเปล่าลงไปให้เองโดยอัตโนมัติครับ (เปิดไฟล์ &lt;code&gt;hello.py&lt;/code&gt; เพื่อศึกษาผลลัพท์)&lt;br /&gt;
&lt;br /&gt;
เสร็จแล้วก็อย่าลืมลบ branch ทิ้งนะครับ&lt;br /&gt;
&lt;script class="brush: bash" type="syntaxhighlighter"&gt;
$ git branch show-help sort-name -d
Deleted branch show-help (was 052a17b).
Deleted branch sort-name (was a973745).
&lt;/script&gt;</description><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total></item><item><title>Git: รวม branch เข้าด้วยกัน</title><link>http://tutor0x.blogspot.com/2012/07/git-branch_27.html</link><category>Git</category><author>noreply@blogger.com (nz)</author><pubDate>Fri, 27 Jul 2012 15:50:00 +0700</pubDate><guid isPermaLink="false">tag:blogger.com,1999:blog-3074227793814140422.post-2905139169009040340</guid><description>การแตก branch นั้นช่วยเก็บรักษา code รุ่นที่ยังทำงานถูกต้องไว้ก็จริง แต่มันจะไม่มีประโยชน์เลยถ้าจะแตก branch ต่อไปกันเรื่อยๆ เพราะสุดท้ายเราจะไม่รู้เลยว่า branch ไหนมีความสำคัญอย่างไร code ที่เพิ่มมาใน branch ย่อยๆ เมื่อทดสอบว่าทำงานได้ถูกต้องสมบูรณ์แล้ว ควรถูกย้ายกลับมาอยู่ใน branch master ครับ&lt;br /&gt;
&lt;br /&gt;
ตอนนี้จะเขียนโปรแกรมให้รับ argument เป็นชื่อคนจาก command line แล้วเปลี่ยนไปทักทายคนเหล่านั้นแทน&lt;br /&gt;
&lt;script class="brush: bash" type="syntaxhighlighter"&gt;
$ git checkout -b hi-name
Switched to new branch 'hi-name'
&lt;/script&gt;&lt;br /&gt;
สร้าง branch ใหม่เช่นเคย (สังเกตว่าเปลี่ยนไปใช้ &lt;code&gt;checkout -b&lt;/code&gt; ซึ่งเป็นรูปย่อของการสร้าง branch พร้อม checkout) แล้วแก้ไขไฟล์ &lt;code&gt;hello.py&lt;/code&gt; เป็นดังนี้&lt;br /&gt;
&lt;script class="brush: python" type="syntaxhighlighter"&gt;
import sys

names = sys.argv[1:]

if not names:
    print("Hello, world!")

for name in names:
    print("Hi {}".format(name))
&lt;/script&gt;&lt;br /&gt;
ทดสอบโปรแกรมกันหน่อย&lt;br /&gt;
&lt;script class="brush: bash" type="syntaxhighlighter"&gt;
$ python hello.py
Hello, world!
$ python hello.py Jack Evan Biz
Hi Jack.
Hi Evan.
Hi Biz.
&lt;/script&gt;&lt;br /&gt;
โปรแกรมทำงานได้ตามที่ออกแบบไว้ ก็ได้เวลา commit เข้าระบบ&lt;br /&gt;
&lt;script class="brush: bash" type="syntaxhighlighter"&gt;
$ git commit -am 'accept cli args as names'
[hi-name 9824537] accept cli args as names
 1 file changed, 10 insertions(+), 1 deletion(-)
&lt;/script&gt;&lt;br /&gt;
เรียบร้อยแล้วสลับกลับมาที่ branch master และสั่ง merge (รวม branch) hi-name กับ master เข้าด้วยกัน&lt;br /&gt;
&lt;script class="brush: bash" type="syntaxhighlighter"&gt;
$ git checkout master 
Switched to branch 'master'
$ git merge hi-name 
Updating b2b0e96..9824537
Fast-forward
 hello.py |   11 ++++++++++-
 1 file changed, 10 insertions(+), 1 deletion(-)
&lt;/script&gt;&lt;br /&gt;
เพียงเท่านี้ที่ branch master ก็จะได้รับ code ที่เพิ่ม feature ใหม่ๆ มาจาก branch ที่แตกไปแล้วครับ&lt;br /&gt;
&lt;br /&gt;
อันที่จริง ถ้าสังเกตดูรายงาน จะเห็นว่าเป็นการ Fast-forward ซึ่งหมายถึงหมายเลข commit ของ branch master ย้ายไปใช้ตัวเดียวกับของ hi-name เท่านั้นเอง ยังไม่ใช่การ merge ที่แท้จริงแต่อย่างใด&lt;br /&gt;
&lt;br /&gt;
และเนื่องจากตอนนี้ branch hi-name ก็ได้ทำหน้าที่ของมันเรียบร้อยแล้ว สั่งลบได้เลยครับ&lt;br /&gt;
&lt;script class="brush: bash" type="syntaxhighlighter"&gt;
$ git branch hi-name -d
Deleted branch hi-name (was 9824537).
&lt;/script&gt;&lt;br /&gt;
สังเกตว่าเปลี่ยนไปใช้ &lt;code&gt;-d&lt;/code&gt; (ตัวเล็ก) แทน ซึ่งตัวเลือกนี้จะเช็คดูให้แน่ในก่อนว่า branch นั้นถูก merge เรียบร้อยแล้วถึงจะลบทิ้งได้ครับ</description><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">1</thr:total></item><item><title>Git: แตก branch</title><link>http://tutor0x.blogspot.com/2012/07/git-branch.html</link><category>Git</category><author>noreply@blogger.com (nz)</author><pubDate>Thu, 26 Jul 2012 17:53:00 +0700</pubDate><guid isPermaLink="false">tag:blogger.com,1999:blog-3074227793814140422.post-2418232836329533169</guid><description>จุดแข็งที่ทำให้เราต้องใช้โปรแกรมจำพวก SCM คือความสามารถในการกู้คืนความเสียหายให้กลับมาเป็นเหมือนเดิม&lt;br /&gt;
&lt;br /&gt;
การแตก branch ก็เป็นหนึ่งในจุดแข็งนี้ คอนเซ็ปง่ายๆ ของมันคือทำสำเนาไฟล์ทั้งหมด แล้วก็ทำงานในไฟล์ที่สำเนามานั่นเอง ถ้าแก้ไขต่อเติมไฟล์แล้วผลลัพท์ออกมาไม่ดี ก็สามารถลบ branch นั้นๆ ทิ้งได้โดยไม่กระทบกับโปรเจคหลัก&lt;br /&gt;
&lt;br /&gt;
ลองแตก branch จากโปรเจค hello โดยให้ชื่อว่า polyglot สามารถสั่งได้ดังนี้&lt;br /&gt;
&lt;script class="brush: bash" type="syntaxhighlighter"&gt;
$ git branch polyglot
&lt;/script&gt;&lt;br /&gt;
และดู branch ที่มีด้วย&lt;br /&gt;
&lt;script class="brush: bash" type="syntaxhighlighter"&gt;
$ git branch
* master
  polyglot
&lt;/script&gt;&lt;br /&gt;
จะเห็นว่ามี branch master กับ polyglot โดยตอนนี้อยู่ที่ branch master ซึ่งเป็น branch หลักที่ Git สร้างไว้ให้ โดย branch นี้ควรจะเก็บโปรเจคช่วงที่ stable เอาไว้ครับ&lt;br /&gt;
&lt;br /&gt;
ตอนนีเรารู้แล้วว่าต้องการทำงานที่ branch polyglot ก็สามารถสลับ branch ไปได้โดยสั่ง&lt;br /&gt;
&lt;script class="brush: bash" type="syntaxhighlighter"&gt;
$ git checkout polyglot
Switched to branch 'polyglot'
&lt;/script&gt;&lt;br /&gt;
จะทดลองลอง&lt;a href="http://en.wikipedia.org/wiki/Polyglot_(computing)"&gt;เขียนโปรแกรมแบบรองรับหลายภาษา&lt;/a&gt; โดยแก้ไขไฟล์ &lt;code&gt;hello.py&lt;/code&gt; กันนิดหน่อย ให้เป็นดังนี้&lt;br /&gt;
&lt;script class="brush: python" type="syntaxhighlighter"&gt;
#include&lt;stdio.h&gt;
#define print(x) using namespace std; /*
#*/ int main(void){return printf(x"\n");}
print("Hello, world!")
&lt;/script&gt;&lt;br /&gt;
เรียบร้อยแล้วคอมไพล์เป็น C++ และทดสอบการทำงานทั้ง 2 ภาษาดู&lt;br /&gt;
&lt;script class="brush: bash" type="syntaxhighlighter"&gt;
$ cc -x c++ hello.py
$ ./a.out
Hello, world!
$ python hello.py
Hello, world!
&lt;/script&gt;&lt;br /&gt;
ทำงานได้ผ่านเรียบร้อยก็เตรียมตัว commit code ซึ่งถ้าลองตรวจสถานะโปรเจคดู จะพบว่ามีไฟล์ &lt;code&gt;a.out&lt;/code&gt; ซึ่งจะไม่ถูกจำเข้าระบบด้วย&lt;br /&gt;
&lt;script class="brush: bash" type="syntaxhighlighter"&gt;
$ git status 
# On branch polyglot
# Changes not staged for commit:
#   (use "git add &lt;file&gt;..." to update what will be committed)
#   (use "git checkout -- &lt;file&gt;..." to discard changes in working directory)
#
# modified:   hello.py
#
# Untracked files:
#   (use "git add &lt;file&gt;..." to include in what will be committed)
#
# a.out
no changes added to commit (use "git add" and/or "git commit -a")
&lt;/script&gt;&lt;br /&gt;
เนื่องจากไฟล์ &lt;code&gt;a.out&lt;/code&gt; เกิดจากการคอมไพล์ไฟล์ &lt;code&gt;hello.py&lt;/code&gt; และยังไม่มีความจำเป็นต้องใช้ในเวลานี้ เราอาจสั่งให้ Git ลบไฟล์ทั้งหมดที่ไม่รู้จักโดย&lt;br /&gt;
&lt;script class="brush: bash" type="syntaxhighlighter"&gt;
$ git clean -f
Removing a.out
&lt;/script&gt;&lt;br /&gt;
ถึงตรงนี้ ก็พร้อม commit แล้ว ซึ่งถ้าไม่อยากเสียเวลาไล่สั่ง add ไฟล์ที่แก้ไข สามารถใส่ &lt;code&gt;-a&lt;/code&gt; เพื่อบอกให้ add ไฟล์เหล่านั้นแบบอัตโนมัติได้ครับ&lt;br /&gt;
&lt;script class="brush: bash" type="syntaxhighlighter"&gt;
$ git commit -am 'polyglot code work in c++'
[polyglot 7741c77] polyglot code work in c++
 1 file changed, 3 insertions(+)
&lt;/script&gt;&lt;br /&gt;
&lt;hr /&gt;&lt;br /&gt;
แต่เนื่องจาก branch polyglot นี้ มันค่อนข้างพัฒนาโปรแกรมต่อได้ยาก เราจะลบ branch นี้ทิ้งไปครับ โดยก่อนอื่นต้องเปลี่ยนไปอยู่ branch master ก่อน แล้วสั่งลบด้วยคำสั่งนี้&lt;br /&gt;
&lt;script class="brush: bash" type="syntaxhighlighter"&gt;
$ git checkout master 
Switched to branch 'master'
$ git branch polyglot -D
Deleted branch polyglot (was 7741c77).
&lt;/script&gt;</description><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total></item><item><title>Git: จัดการไฟล์พื้นฐาน</title><link>http://tutor0x.blogspot.com/2012/07/git.html</link><category>Git</category><author>noreply@blogger.com (nz)</author><pubDate>Wed, 25 Jul 2012 19:15:00 +0700</pubDate><guid isPermaLink="false">tag:blogger.com,1999:blog-3074227793814140422.post-7603161276497685821</guid><description>ตอนก่อนเราได้สวัสดีชาวโลกกันไปแล้ว แต่จะเห็นว่าไวยากรณ์ผิดพลาดอยู่บ้าง ลองแก้ไฟล์ &lt;code&gt;hello.py&lt;/code&gt; เป็น&lt;br /&gt;
&lt;script class="brush: python" type="syntaxhighlighter"&gt;
print("Hello, world!")
&lt;/script&gt;&lt;br /&gt;
พร้อมกับเขียนไฟล์ใหม่ชื่อ &lt;code&gt;README.md&lt;/code&gt; เพื่อบอกข้อมูลพื้นฐานของโปรแกรมนี้ โดยมีเนื้อหาว่า&lt;br /&gt;
&lt;script class="brush: plain" type="syntaxhighlighter"&gt;
Yet Another Hello World Program
===============================

This program simply say "Hello, world!"

&lt;/script&gt;&lt;br /&gt;
และอีกไฟล์ชื่อ &lt;code&gt;MANUAL.md&lt;/code&gt;&lt;br /&gt;
&lt;script class="brush: plain" type="syntaxhighlighter"&gt;
Start this program by:
    
    $ python hello.py

&lt;/script&gt;&lt;br /&gt;
ลองเช็คสถานะของโปรเจคนี้ดู จะได้ผลลัพท์ดังนี้&lt;br /&gt;
&lt;script class="brush: bash" type="syntaxhighlighter"&gt;
$ git status
# On branch master
# Changes not staged for commit:
#   (use "git add &lt;file&gt;..." to update what will be committed)
#   (use "git checkout -- &lt;file&gt;..." to discard changes in working directory)
#
# modified:   hello.py
#
# Untracked files:
#   (use "git add &lt;file&gt;..." to include in what will be committed)
#
# MANUAL.md
# README.md
no changes added to commit (use "git add" and/or "git commit -a")
&lt;/script&gt;&lt;br /&gt;
ซึ่งบอกว่า ทั้งไฟล์ &lt;code&gt;hello.py&lt;/code&gt; ที่เพิ่งแก้ไขไป และไฟล์ &lt;code&gt;MANUAL.md&lt;/code&gt;, &lt;code&gt;README.md&lt;/code&gt; ที่เพิ่มมาใหม่นั้น จะไม่ถูกจำสำหรับการ commit ในครั้งถัดไป&lt;br /&gt;
&lt;br /&gt;
ดังนั้น เราต้องเพิ่มไฟล์ทั้งสองเข้าไปในระบบก่อน โดยสั่ง add เหมือนตอนที่แล้วครับ&lt;br /&gt;
&lt;script class="brush: bash" type="syntaxhighlighter"&gt;
$ git add hello.py MANUAL.md README.md
&lt;/script&gt;&lt;br /&gt;
เช็คสถานะไฟล์อีกครั้ง&lt;br /&gt;
&lt;script class="brush: bash" type="syntaxhighlighter"&gt;
$ git status
# On branch master
# Changes to be committed:
#   (use "git reset HEAD &lt;file&gt;..." to unstage)
#
# new file:   MANUAL.md
# new file:   README.md
# modified:   hello.py
#
&lt;/script&gt;&lt;br /&gt;
พร้อมแล้วก็สั่ง commit เลยครับ&lt;br /&gt;
&lt;script class="brush: bash" type="syntaxhighlighter"&gt;
$ git commit -m 'init project'
[master d918f10] init project
 3 files changed, 9 insertions(+), 1 deletion(-)
 create mode 100644 MANUAL.md
 create mode 100644 README.md
&lt;/script&gt;&lt;br /&gt;
&lt;hr /&gt;&lt;br /&gt;
แต่ตอนนี้เราจะเห็นว่า ไฟล์ &lt;code&gt;MANUAL.md&lt;/code&gt; และ &lt;code&gt;README.md&lt;/code&gt; นั้น มีเนื้อหาน้อยมาก และสามารถจับเอามารวมกันได้ แก้ไขไฟล์ &lt;code&gt;README.md&lt;/code&gt; เป็นดังนี้&lt;br /&gt;
&lt;script class="brush: plain" type="syntaxhighlighter"&gt;
Yet Another Hello World Program
===============================

This program simply say "Hello, world!"

Start program by:

    $ python hello.py

&lt;/script&gt;&lt;br /&gt;
ถึงตอนนี้ เราจะไม่ต้องการไฟล์ &lt;code&gt;MANUAL.md&lt;/code&gt; แล้ว ก็สั่งลบไฟล์ออกจากระบบโดย&lt;br /&gt;
&lt;script class="brush: bash" type="syntaxhighlighter"&gt;
$ git rm MANUAL.md
&lt;/script&gt;&lt;br /&gt;
จะเห็นว่าไฟล์ &lt;code&gt;MANUAL.md&lt;/code&gt; หายไปจากไดเรคทอรี่เป็นที่เรียบร้อย ตอนนี้ก็ได้เวลาสั่ง commit งานที่เพิ่งแก้ไขกันครับ&lt;br /&gt;
&lt;script class="brush: bash" type="syntaxhighlighter"&gt;
$ git add README.md
$ git commit -m 'improve README'
[master b2b0e96] improve READMEไฟล์
 2 files changed, 5 insertions(+), 4 deletions(-)
 delete mode 100644 MANUAL.md
&lt;/script&gt;&lt;br /&gt;
อย่าลืมว่าก่อน commit ต้อง add ไฟล์ที่ถูกแก้ไขทุกครั้งนะครับ</description><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">2</thr:total></item><item><title>PHP: Send mail</title><link>http://tutor0x.blogspot.com/2012/07/php-send-mail.html</link><category>PHP</category><author>noreply@blogger.com (Unknown)</author><pubDate>Wed, 25 Jul 2012 17:01:00 +0700</pubDate><guid isPermaLink="false">tag:blogger.com,1999:blog-3074227793814140422.post-3301564994951767686</guid><description>การใช้ PHP ส่งเมลนั้นทำได้ง่ายมาก อาจจะเป็นภาษาที่ส่งเมลได้ง่ายที่สุดในบรรดาภาษาคอมพิวเตอร์ที่มีอยู่ในโลก ฟังชั่นที่ใช้ส่งเมลคือ &lt;a href="http://php.net/manual/en/function.mail.php"&gt;&lt;code&gt;mail()&lt;/code&gt;&lt;/a&gt;

&lt;blockquote&gt;&lt;code&gt;&lt;strong&gt;mail&lt;/strong&gt; ( $to, $subject, $message [, $headers[ , $additional_param] ] )&lt;/code&gt;&lt;/blockquote&gt;

พารามิเตอร์ที่จำเป็นมีอยู่ 3 ตัว และพารามิเตอร์เสริม 2 ตัว คือ
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;$to&lt;/code&gt; ที่อยู่อีเมลผู้รับ&lt;/li&gt;
&lt;li&gt;&lt;code&gt;$subject&lt;/code&gt; หัวข้อของอีเมล&lt;/li&gt;
&lt;li&gt;&lt;code&gt;$message&lt;/code&gt; เป็นเนื้อหาของอีเมล&lt;/li&gt;
&lt;li&gt;&lt;code&gt;$headers&lt;/code&gt; เป็นพารามิเตอร์เสริม เอาไว้กำหนดหัวเมลเพิ่มเติม&lt;/li&gt;
&lt;li&gt;&lt;code&gt;$additional_param&lt;/code&gt; เป็นพารามิเตอร์เสริม สำหรับส่งค่าให้กับโปรแกรมส่งเมล (ไม่ค่อยได้ใช้)&lt;/li&gt;
&lt;/ul&gt;

การขึ้นบรรทัดใหม่ในเมลนั้นจะใช้ &lt;code&gt;\r\n&lt;/code&gt; (เหมือนการขึ้นบรรทัดใหม่ในโปรแกรมของฝั่ง Windows) แทนที่จะใช้ &lt;code&gt;\n&lt;/code&gt; อย่างเดียว ไม่ว่าจะส่งจาก OS ที่เป็น Windows หรือ Linux
&lt;script class="brush: php" type="syntaxhighlighter"&gt;
&lt;?php
    $to = 'totor0x@example.com';
    $subject = 'Want to be a contributor';
    $message = 'I think your blog is great ';
    $message .= 'and I want to be a contributor of this blog.';
    $message .= "\r\n\r\n";
    $message .= 'Best regards';

    mail($to, $subject, $message); // send!
&lt;/script&gt;
แค่นี้ก็จบ&lt;br /&gt;
&lt;br /&gt;
แต่ถ้าต้องการระบุอีเมลที่ใช้ส่ง รวมทั้งการใช้เนื้อหาในอีเมลเป็น HTML จะต้องใส่ &lt;code&gt;$headers&lt;/code&gt; ลงไปด้วย
&lt;script class="brush: php" type="syntaxhighlighter"&gt;
&lt;?php
    $from = 'me@example.com';
    $to = 'totor0x@example.com';

    $subject = 'Want to be a contributor';

    $headers = 'From: ' . $from . "\r\n"; // sender
    $headers .= 'Reply-To: ' . $form . "\r\n"; // usually sender
    $headers .= "MIME-Version: 1.0\r\n";
    $headers .= "Content-Type: text/html; charset=utf-8\r\n";

    $message = '&lt;style&gt;.center {text-align: center;}&lt;/style&gt;';
    $message .= '&lt;div class="center"&gt;I think your blog is great ';
    $message .= 'and I want to be a contributor of this blog.&lt;/div&gt;';
    $message .= "\r\n\r\n";
    $message .= '&lt;strong&gt;Best regards&lt;/strong&gt;';

    mail($to, $subject, $message, $headers); // send!
&lt;/script&gt;

ข้อจำกัดของอีเมลที่ควรรู้ไว้คือ
&lt;ul&gt;
&lt;li&gt;แนบ JavaScript ลงไปไม่ได้ (ที่จริงก็แนบได้ แต่โปรแกรมอ่านเมลทั้งหลายปิดการทำงานของ JavaScript ทิ้งเพื่อความปลอดภัย)&lt;/li&gt;
&lt;li&gt;หากใช้ CSS จะต้องแทรกลงไปในเนื้อหาอีเมล ไม่สามารถแนบเป็นไฟล์ภายนอกไปได้&lt;/li&gt;
&lt;li&gt;หากต้องการแทรกรูปภาพจะต้องใช้พาธเต็ม แต่หากไม่จำเป็นก็ไม่ควรจะใส่ลงไป&lt;/li&gt;
&lt;/ul&gt;</description><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total></item><item><title>Git: มารู้จักกับโปรแกรมบริหารซอร์สกันเถอะ</title><link>http://tutor0x.blogspot.com/2012/07/git_24.html</link><category>Git</category><author>noreply@blogger.com (nz)</author><pubDate>Tue, 24 Jul 2012 00:01:00 +0700</pubDate><guid isPermaLink="false">tag:blogger.com,1999:blog-3074227793814140422.post-7667840538439804614</guid><description>1969 &lt;a href="http://en.wikipedia.org/wiki/Linus_Torvalds"&gt;Linus Torvalds&lt;/a&gt; (คนเดียวกับผู้สร้าง Linux) เกิด&lt;br /&gt;
1972 กำเนิดโปรแกรม &lt;a href="http://en.wikipedia.org/wiki/Source_Code_Control_System"&gt;SCCS&lt;/a&gt; โปรแกรมจัดการซอร์สโปรแกรมแรกๆ&lt;br /&gt;
1990 กำเนิดโปรแกรม &lt;a href="http://en.wikipedia.org/wiki/Concurrent_Versions_System"&gt;CVS&lt;/a&gt;&lt;br /&gt;
2000 กำเนิดโปรแกรม &lt;a href="http://en.wikipedia.org/wiki/Apache_Subversion"&gt;SVN&lt;/a&gt;&lt;br /&gt;
2005 Linus ให้กำเนิด &lt;a href="http://en.wikipedia.org/wiki/Git_(software)"&gt;Git&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;hr /&gt;&lt;br /&gt;
Git เป็นโปรแกรมบริหารจัดการซอร์สตัวหนึ่ง เนื่องจากในการพัฒนาโปรแกรมนั้น เราอาจมีการลองผิดลองถูกอยู่หลายทางว่าได้ผลลัพท์เป็นที่น่าพอใจหรือไม่ หรือบางครั้งฟีเจอร์ใหม่ๆ ที่เพิ่มเข้าไปอาจจะทำให้ระบบล่ม ต้องถอยกลับไปก่อนหน้าที่จะเกิดข้อผิดพลาดนั้น การใช้โปรแกรมบริหารซอร์สจะช่วยให้เราแก้ไขปัญหาต่างๆ ได้อย่างมีประสิทธิภาพมากขึ้น&lt;br /&gt;
&lt;br /&gt;
โดย Git นั้นเป็น&lt;a href="http://en.wikipedia.org/wiki/Distributed_revision_control"&gt;โปรแกรมบริหารซอร์สแบบกระจายศูนย์&lt;/a&gt; ที่จะแจกซอร์สทั้งหมดให้ผู้ใช้ทุกคนเหมือนกัน ไม่แบ่งแยกชนชั้นครับ (ถ้าใครเป็น CVS/SVN มาก่อน ก็อาจถือได้ว่าต้องเรียนรู้ใหม่เกือบหมดเลยทีเดียว)&lt;br /&gt;
&lt;br /&gt;
ผู้ใช้ Windows สามารถใช้ &lt;a href="http://code.google.com/p/msysgit/"&gt;msysGit&lt;/a&gt; แทนได้ (โปรแกรมจะไปรันบน MinGW อีกที)&lt;br /&gt;
&lt;br /&gt;
ส่วนผู้ใช้ Linux ก็เช่นเคย &lt;code&gt;apt-get install git&lt;/code&gt; กันได้เลย&lt;br /&gt;
&lt;br /&gt;
หลังจากติดตั้งโปรแกรมเรียบร้อยแล้ว ก็ต้องตั้งค่าเริ่มต้นที่จำเป็นกันหน่อย โดยสั่ง&lt;br /&gt;
&lt;script class="brush: bash" type="syntaxhighlighter"&gt;
$ git config --global user.name 'Name Surname'
$ git config --global user.email 'name@example.com'
&lt;/script&gt;&lt;br /&gt;
&lt;hr /&gt;&lt;br /&gt;
ลองเริ่มใช้โปรแกรมเลยดีกว่า สมมติจะสร้างโปรเจค &lt;code&gt;hello&lt;/code&gt; ก็สั่งดังนี้&lt;br /&gt;
&lt;script class="brush: bash" type="syntaxhighlighter"&gt;
$ mkdir hello
$ cd hello
$ git init
Initialized empty Git repository in ~/hello/.git/
&lt;/script&gt;&lt;br /&gt;
Git จะสร้างไดเรกทอรี &lt;code&gt;.git/&lt;/code&gt; พร้อมไฟล์ระบบต่างๆ ของโปรเจคนี้ให้ครับ&lt;br /&gt;
&lt;br /&gt;
คราวนี้มาเขียนโปรแกรมหลักของโปรเจคนี้กัน&lt;br /&gt;
&lt;script class="brush: bash" type="syntaxhighlighter"&gt;
$ echo 'print("hello world!")' &gt; hello.py
$ python hello.py
hello world!
&lt;/script&gt;&lt;br /&gt;
ทดสอบแล้วรันได้ไม่มีปัญหา ก็ได้เวลาสั่งให้ Git จำ code เข้าระบบโดย&lt;br /&gt;
&lt;script class="brush: bash" type="syntaxhighlighter"&gt;
$ git add hello.py
$ git commit -m 'init program'
[master (root-commit) 2dd5f8a] init program
 1 files changed, 1 insertions(+)
 create mode 100644 hello.py
&lt;/script&gt;&lt;br /&gt;
เท่านี้ก็เรียบร้อยครับ&lt;br /&gt;
&lt;br /&gt;
ปล. โปรแกรมบริหารซอร์สแบบนี้ ใช้คนเดียวยังไงก็ไม่สนุก อย่างลืมชวนเพื่อนๆ มา code เล่นด้วยกันนะครับ</description><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total></item></channel></rss>