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 อีกทีนะครับ

No comments:

Post a Comment