2011/11/16

.NET Framework - #2 Windows Application


สวัสดีครับ เป็นยังไงกันบ้างครับ
วันนี้เราจะมาสร้าง Form ใน Windows กันครับ

เหมือนเดิมนะครับ ให้สร้าง Project เปล่า ๆ ขึ้นมา แล้วก็เพิ่ม References 3 ตัวคือ System, System.Drawing และ System.Windows.Forms

สำหรับ C++/CLI ให้เพิ่มตรง Project Properties นะครับ


F#, C#, VB.NET ก็เพิ่มตรง References ได้เลยครับ



แล้วก็ไปตั้งค่าอีกนิดนึงครับ
C#, VB.NET, F# ให้เข้าไปที่ Project Properties แล้วตั้ง Output type เป็น Windows Application



ส่วน C++/CLI ให้เข้าไปที่ Project Properties, ในส่วนของ Linker ตรง System เปลี่ยน SubSystem เป็น Windows และตรง Advanced เปลี่ยน Entry Point เป็น main




ตั้งค่าเสร็จแล้ว ก็มาเขียนโค้ดกันเลยครับ~~~~!!!


C++/CLI

using namespace System;
using namespace System::Drawing;
using namespace System::Windows::Forms;

[STAThread]
int main()
{
    Form ^f = gcnew Form();
    f->Text = "C++/CLI Form";
    Application::Run(f);
    return 0;
}


C#

using System;
using System.Drawing;
using System.Windows.Forms;

class Program
{
    [STAThread]
    static void Main()
    {
        Form f = new Form();
        f.Text = "C# Form";
        Application.Run(f);
    }
}


VB.NET

Option Strict On
Option Explicit On

Imports System
Imports System.Drawing
Imports System.Windows.Forms

Module Program
    <STAThread>
    Sub Main()
        Dim f As New Form()
        f.Text = "VB.NET Form"
        Application.Run(f)
    End Sub
End Module


F#

open System
open System.Drawing
open System.Windows.Forms

[<STAThread>]
let f = new Form(Text = "F# Form")
Application.Run(f)



เป็นยังไงกันบ้างครับ เห็นไหมครับว่าภาษา .NET เหมือนกันโค้ดแทบไม่ต่างกันเลย ต่างกันแค่ไวยากรณ์ของภาษานั้น ๆ

วันนี้ก็เอาไว้เท่านี้นะครับ ขอให้สนุกกับการเขียนโปรแกรมครับผม ^w^

(โปรแกรมที่ผมใช้วันนี้คือ Visual Studio 11 Developer Preview นะครับ)

2011/11/11

F# - #3

สวัสดีครับ วันนี้เราก็มาฝึกเขียนภาษา F# กันเหมือนเดิมนะครับ
ก่อนอื่นผมจะขอพูดเกี่ยวกับฟังก์ชันอีกหน่อยนะครับ
คราวนี้ให้เปิดตัว F# Interactive (Console) นะครับ



แล้วลองพิมพ์ลงไปว่า

let f a b = a + b;;
let g(a, b) = a + b;;

จะเห็นว่า f กับ g จะไม่เหมือนกัน
ลองมาดูที่ฟังก์ชัน f กันก่อน

val f : int -> int -> int

หมายถึง f จะรับค่า int 2 ตัว แล้วส่งค่า int กลับมา
ส่วน g

val g : int * int -> int

หมายถึง g จะรับค่า int * int ที่เป็น tuple แล้วจะส่งค่า int กลับออกมา



คราวนี้เราลองมากำหนดชนิดของค่าที่รับเข้าไปกัน

let f (a : float) (b : float) = a + b;;

val f : float -> float -> float

จะเห็นว่าผลลัพท์ (ค่าที่ฟังก์ชันส่งกลับมา) จะเปลี่ยนด้วย

คราวนี้เรากลับมาที่ Visual Studio กันนะครับ
วันนี้เราจะมาดูวิธีเขียนเงื่อนไขกัน

let a = 10
if a < 20 then
    printfn "a < 20"
else
    printfn "a >= 20"

วิธีเขียนจะคล้าย ๆ Object Pascal กับ VB.NET

ส่วนเครื่องหมายจะมี
= เท่ากับ
< น้อยกว่า
> มากกว่า
<> ไม่เท่ากับ

แต่ถ้ามีหลายเงื่อนไข จะใช้ && (and) กับ || (or) เป็นตัวเชื่อม และ elif จะหมายถึง else if

let a = 10
if a < 20 && a >= 0 then
    printfn "0 <= a < 20"
elif a >= 20 then
    printfn "a >= 20"
else
    printfn "a < 0"

คราวนี้มาดูวิธีตรวจสอบค่ากันบ้าง ที่ในภาษา C/C++, C# เป็น switch case แต่ใน F# จะใช้ match with

let a = 4
match a with
| 0 -> printfn "Zero"
| 1 -> printfn "One"
| 2 | 3 -> printfn "2 or 3"
| x when a > 3 -> printfn "%i" x
| _ when a < -4 -> printfn "< -4"
| _ -> printfn "Other"

เครื่องหมาย | (pipe) จะเหมือนกับ case ในภาษา C#
| x when a > 3 หมายถึง ให้ค่าเป็น x ถ้า a > 3 หรือจะเขียนเป็น | x when x > 3 ก็ได้
| _ when a < -4 ไม่สามารถเขียนเป็น _ when _ < -4 ได้
นอกจากนี้ยังเขียนเป็น | x when x > 3 && x < 6 ได้อีกด้วย

ลองเขียนเคสอื่น ๆ ดูนะครับ

คราวนี้ลองมาดู resursive function (ฟังก์ชันเรียกตัวเอง) กันบ้าง

let rec fac n =
    match n with
    | _ when n < 0 -> failwith "n must >= 0"
    | 0 | 1 -> 1
    | _ -> n * fac(n - 1)

เราจะใช้ rec ต่อหลัง let เพื่อบอกว่า ฟังก์ชันที่จะสร้างเป็นฟังก์ชันแบบ recursive ครับ
ส่วน failwith หมายถึง ให้แสดง error ครับ ลองใส่ค่าติดลบดูก็ได้ครับ
ส่วนที่ต้องใส่วงเล็บ ตรง fac(n - 1) ก็เพราะว่า ถ้าเราเขียนเป็น n * fac n - 1 มันจะกลายเป็น n * fac(n) - 1

คราวนี้เราลองมารับค่ากันบ้างครับ
ก่อนอื่นเราต้องเรียก namespace System ขึ้นมาก่อน ด้วยคำสั่ง open เหมือนกับ using ใน C# และ Import ใน VB.NET

open System

printf "Enter a number: "
let a = int(Console.ReadLine())
printfn "%i" a

คราวนี้ถ้าจะรับข้อความเข้ามาทั้งบรรทัด

open System

printf "Enter a string: "
let a = Console.ReadLine()
printfn "%s" a

และเราจะแยกข้อความออกจากกันถ้าเจอเว้นวรรค

open System

printf "Enter a string: "
let a = Console.ReadLine().Split()
printfn "%A" a

ตอนนี้เราจะได้ a เป็น array นะครับ จึงไม่สามารถใช้ %s กับ a ได้
จากตรงนี้ลองพิมพ์ข้อความลงไปว่า Hello World
เราจะได้ [|"Hello"; "World"|]
ซึ่งเราจะเขียนแบบนี้ตอนสร้าง array ครับ

let a = [|1; 2; 3; 4|]
printfn "%A" a

สมาชิกแต่ละตัวจะใช้ ; (semi-colon) เป็นคั่น และใช้ [|   |] ครอบ

แล้วถ้าต้องการรับค่าเข้ามาแล้วแปลงเป็น int หล่ะจะทำยังไง
เช่น ใส่ค่าเข้ามาว่า 1 6 12 จะให้รับเข้ามาเป็น array [|1; 6; 12|]

open System

printf "Enter a string: "
let a = Array.map(fun x -> int x) (Console.ReadLine().Split())
printfn "%A" a

เราจะใช้คำสั่ง Array.map เข้ามาช่วย แล้วเขียนฟังก์ชันข้างใน
หรือจะเขียนว่า

let a = Console.ReadLine().Split() |> Array.map(fun x -> int x)

ก็ได้

แล้วเจ้า |> (pipe + >) มันคืออะไร ?

เครื่องหมาย |> นิยามโดย

let (|>) x f = f x

ลองดูกับฟังก์ชันง่าย ๆ

open System
let a = Math.Cos 5.0
printfn "%f" a

เราจะเขียนเป็น

let a = 5.0 |> Math.Cos

ก็ได้ มีความหมายเหมือนกัน

เริ่มงงกันแล้วใช่ไหมครับ งั้นวันนี้พอแค่นี้ก่อนละกันครับ เดี๋ยวผมจะมาพูดเรื่อง Array อีกทีนะครับ

2011/11/10

F# - #2

สวัสดีครับ วันนี้เราจะมาฝึกเขียนภาษา F# กันอีกเช่นเคย แต่จะเป็นเรื่องอะไร ลองทายดูสิครับ
...
วันนี้เราจะมาเขียนฟังก์ชันกันครับ !!!!
อ่านถูกแล้วหล่ะครับ มันคือฟังก์ชัน นั้นแหละครับ
บางคนอาจจะงง ยังไม่ทันไรก็ขึ้นฟังก์ชันแล้ว ?
จริง ๆ แล้วฟังก์ชันในภาษา F# นั้นสร้างไม่ยากเลยครับ เพราะว่าใช้คำสั่ง let เหมือนกัน

let myFun() = 5
let a = myFun()
printfn "%A" a

เหมือนกันเลยครับ แต่ต้องใส่ () ต่อท้ายเท่านั้นเอง เราก็จะได้ myFun เป็นฟังก์ชันแล้ว... เย้

ต่อไปมาลองสร้างฟังก์ชันที่มีการรับค่าเข้าไปดูครับ

let add a b = a + b
let r = add 6 4
printfn "%A" r

เป็นยังไงบ้างครับ ง่ายใช่ไหมหล่ะครับ

แล้วถ้าฟังก์ชันมีหลายบรรทัดหล่ะ จะเขียนยังไงดี ?

ก่อนอืนเลยต้องบอกว่า scope ใน F# จะใช้ย่อหน้าครับ เช่นในภาษา C/C++, C# จะเป็น { } ใน Object Pascal เป็น begin end; เป็นต้น

let f x =
    let r1 = x * x
    let r2 = r1 + 20
    r2
printfn "%A" (f 6)

จะเห็นว่าคำสั่งที่อยู่ในย่อหน้า ตั้งแต่ let r1 จนถึง r2 จะเป็นคำสั่งในฟังก์ชัน f ครับ

ลองมาดูกันทีละบรรทัดนะครับ
let f x =

หมายถึง สร้างฟังก์ชัน f ที่รับค่า x เข้าไป
    let r1 = x * x
    let r2 = r1 + 20

คือการสร้างค่าคงที่ ที่อยู่ในฟังก์ชันครับ เพราะฉะนั้นเราจึงใช้ r1 กับ r2 ได้แค่ในฟังก์ชัน f เท่านั้น

    r2

คือการส่งค่ากลับออกมาให้ฟังก์ชันครับ คล้าย ๆ กับ return r2; ในภาษา C/C++, C# ฯลฯ

นอกจากนี้เรายังสามารถประกาศค่าคงที่ ที่ชื่อซ้ำกันในฟังก์ชันได้อีกด้วย

let f x =
    let r = x * x
    let r = r + 20
    r

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

let f(x) =
    let r = x * x
    let r = r + 20
    r
printfn "%A" (f(6))

นอกจากนี้ยังสามารถใช้ชื่อซ้ำกันใน scope ที่ซ้อนกันได้

let f x =
    let r =
        let r = x * x
        r + 1
    r * 2
printfn "%A" (f 3)

จะเห็นว่าตำสั่ง r + 1 จะหมายถึง r ที่เป็น x * x และ r * 2 จะหมายถึง r ตัวแรกที่อยู่หลัง let f x


Tuple คืออะไร ? http://en.wikipedia.org/wiki/Tuple

ลองดูตัวอย่างกันดีกว่าครับ
let (a, b) = (1, 2) // หรือ let a, b = 1, 2
printfn "a = %A" a
printfn "b = %A" b

เราจะได้ a = 1 และ b = 2 ครับ คิดว่าดูจากตัวอย่างแล้วน่าจะเข้าใจนะครับ

คราวนี้
let a = (1, 2)
printfn "%A" a

ลองรันดูนะครับ แล้วดูว่า a คืออะไร ?

ถ้ารันดูแล้วจะรู้ว่า a จะเท่ากับ (1, 2)

แล้วจะเอาค่าออกมายังไงหล่ะ ?
let a = (1, 2)
let x = fst a
let y = snd a
printfn "x = %A\ny = %A" x y

เราจะใช้ฟังก์ชัน fst เพื่อเอาค่าของตัวแรกออกมา และใช้ snd เพื่อเอาค่าตัวหลังออกมา ซึ่งฟังก์ชันทั้ง 2 ตัวนี้มีอยู่แล้วครับ แต่ถ้าใครจะเขียนเองก็ไม่ยากครับ
let fst(a, b) = a
let snd(a, b) = b

แต่ต้องใส่วงเล็บด้วยนะครับ จะเขียนเป็น fst a b ไม่ได้ เพราะ (a, b) มันคือ tuple ไงครับ

ลองดูตัวอย่างกันอีกหน่อย
let f a b = a + b
let x = f(4, 5)
printfn "%A" x

เราไม่สามารถเขียนแบบนี้ได้นะครับ เพราะ f จะต้องรับค่าเข้าไป 2 ค่า แต่ (4, 5) มันคือ ค่าเดียวครับ
จึงต้องเขียนเป็นแบบนี้
let f(a, b) = a + b
let x = f(4, 5)
printfn "%A" x

และแน่นอนครับว่าแบบข้างล่างนี้ก็ใช้ไม่ได้
let f(a, b) = a + b
let x = f 4 5
printfn "%A" x

เพราะว่า f รับค่าเข้าไปแค่ค่าเดียว คือข้อมูลแบบ tuple (a, b) แต่ f 4 5 หมายถึง ส่ง 4 กับ 5 เข้าไปให้ f


ต่อไปมาดูการละค่ากันครับ
let a = (1, 2)
let x, _ = a
printfn "%A" x

จะได้ x = 1 ครับ เครื่องหมาย _ (underscore) หมายถึงละค่าครับ เพราะฉะนั้นเลข 2 จังไม่ถูกเก็บเข้ามา

และ _ ไม่สามารถตั้งเป็นชื่อได้ เราจึงไม่สามารถ printfn "%A" _ ได้ครับ

2011/11/09

F# - #1

สวัสดีครับ วันนี้เราจะมาหัดเขียนโปรแกรมในภาษา F# กันครับ
ภาษา F# คืออะไร ? ลองดูที่ wikipedia นะครับ http://en.wikipedia.org/wiki/F_Sharp_(programming_language)
ก่อนอื่นเลยเราต้องมาลงเจ้า Compiler กับ IDE กันก่อนนะครับ
ตัว Compiler โหลดได้จาก http://research.microsoft.com/en-us/um/cambridge/projects/fsharp/ หรือถ้าหาไม่เจอก็เข้า http://www.microsoft.com/download/en/details.aspx?displaylang=en&id=18706 ก็ได้ครับ
ส่วน IDE ก็ใช้ Visual Studio 2010 Shell ครับ http://www.microsoft.com/download/en/details.aspx?displaylang=en&id=115
แล้วก็อย่าลืมลง .NET Framework ด้วยนะครับ http://www.microsoft.com/download/en/details.aspx?id=17851
เอาหล่ะ เราลองมาเขียนโปรแกรมแรกกันเลยดีกว่า ลองทายสิว่าโปรแกรมอะไร...

ใช่แล้ว มันก็คือ Hello World นั้นเอง
ก่อนอื่นเลยก็เปิดโปรแกรม Visual Studio 2010 Shell สร้าง Project ใหม่นะครับ เลือกที่ F# Application แล้วกด OK โล้ดดด




แล้วเราจะได้ source code เปล่า ๆ ที่ comment 1 บรรทัด เขียนไว้ว่า
// Learn more about F# at http://fsharp.net

จะลบทิ้งก็ได้นะครับ

สำหรับคนที่เคยเขียนภาษาอื่นมาก่อนเช่น C# หรือ VB.NET อาจจะตกใจเพราะว่าไม่เจอ code อะไรเลย ปกติใน C# หรือ VB.NET เมื่อสร้าง project ใหม่แล้วจะมี template มาให้

เอาละครับ เรามาเขียน code กันเลย

ง่าย ๆ สั้น ๆ ครับ ไม่ต้องสร้าง class ไม่ต้องสร้าง function อะไรเลย แค่พิมพ์ลงไปว่า
printfn "Hello World"

ไม่ต้องตกใจครับ แค่บรรทัดเดียวครับ "code มีแค่บรรทัดเดียว"

เสร็จลองรันดูนะครับ ถ้ารันแบบ Debug (F5) จะมีหน้าต่างดำ ๆ โผล่ออกมาแล้วหายไป ให้รันแบบไม่ใช้ Debug (Ctrl + F5) แทนนะครับ



เป็นยังไงบ้างครับ สั้นดีใช่ไหมหล่ะครับ



เอาหล่ะครับ เรามาสร้างค่าคงที่กันดีกว่าครับ...

แน่นอนครับ ว่ามันคือ "ค่าคงที่"

เราก็เจอกันไปแล้วในโปรแกรมที่เขียนกันเมื่อกี้ ก็คือ "Hello World" นี่แหละ มันคือค่าคงที่ชนิด String นี่แหละครับ



และ!! เราจะใช้คำสั่ง let (ให้) ในการตั้งชื่อให้กับค่าคงที่ครับ
let s = "Hello World"

เราจะได้ s เป็นค่าคงที่ ที่เก็บ "Hello World" เอาไว้

ซึ่งแน่นอนว่า s เป็นค่าคงที่ !! เราจึงไม่สามารถเปลี่ยนแปลงค่า s ได้

นี่คือแนวคิดแบบ functional programming ครับ หรือก็คือ ทุก ๆ อย่างนั้นเป็นค่าคงที่ รวมถึง function ด้วย

เราคงเคยเจอกันมาเยอะแล้ว..

เคยเจอมาเยอะแล้วจริง ๆ ครับ ในวิชาคณิตศาสตร์ยังไงหล่ะครับ เช่น ถ้า a = 10 แล้วเราก็ไม่สามารถเปลี่ยนค่า a ได้ถูกไหมครับ



แต่ F# ไม่ได้เป็น functional language ซะดีเดียว เราจึงสามารถเปลี่ยนแปลงค่าได้

เราจะใช้คำสั่ง mutable (ไม่แน่นอน) ต่อท้าย let ครับ เพื่อให้เราสามารถเปลี่ยนแปลงค่าได้
let mutable a = 6

เราจะได้ a ที่แปลงร่างกลายเป็นตัวแปรแล้ว !

แต่ระวังอย่างหนึ่งนะครับ เครื่องหมาย = ไม่ใช่หมายถึง ให้ a = 6 ซะทีเดียว

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

เช่นถ้าเราเจอ a = 4 โดยที่ไม่มี let แสดงว่า เครื่องหมาย = กำลังทำหน้าที่ตรวจสอบค่าว่า a เท่ากับ 4 รึเปล่า

เพราะฉะนั้นเราจึงไม่สมารถใช้ = เปลี่ยนค่าของ mutable ได้ แต่จะใช้เครื่องหมาย <- (น้อยกว่า + ขีด) แทน
let mutable a = 6
printfn "%A" a
a <- 10
printfn "%A" a

และแน่นอนว่า ตอนนี้ a มีชนิดข้อมูลเป็น int (จำนวนเต็ม) เราไม่สามารถเปลี่ยนค่าให้กลายเป็นอย่างอื่นได้ เช่น
a <- "Text"
a <- 3.2

ทำไม่ได้แน่นอนครับ



แล้ว... %A คืออะไร ?

คนที่เคยเขียนภาษา C/C++ มาก่อนจะรู้ได้ทันทีเลยว่าคืออะไร (รึเปล่า)

มันก็คล้าย ๆ กับ %d %f ในภาษา C/C++ นั้นแหละ

แต่ %A จะดีกว่าหน่อยนึง ก็คือเราจะใส่ค่าอะไรลงไปก็ได้ เดี๋ยวมันจะเรียกฟังก์ชัน ToString() ของค่านั้น ๆ ออกมาให้