Higher Order Function ใน Go

Higher Order Function ใน Go

ในภาษา Go การเขียน Higher-Order Functions (HOF) เริ่มมีความน่าสนใจและใช้งานได้กว้างขวางขึ้นมากหลังจากที่มี Generics (Go 1.18+) เข้ามา เพราะเราไม่ต้องเขียนฟังก์ชันแยกสำหรับทุก Type อีกต่อไป

Higher-Order Functions ใน Go: ยกระดับโค้ดให้ยืดหยุ่นด้วย Generics

ในภาษา Go ฟังก์ชันถือเป็น "First-class citizen" หมายความว่าเราสามารถเก็บฟังก์ชันไว้ในตัวแปร, ส่งเข้าไปในฟังก์ชันอื่น หรือคืนค่าฟังก์ชันออกมาได้ รูปแบบนี้เรียกว่า Higher-Order Functions (HOF) ซึ่งเป็นหัวใจสำคัญของการเขียนโค้ดที่ประกอบร่างได้ (Composable) และทดสอบง่าย (Testable) เรามาดูกันว่าเราสามารถทำ HOF ได้กี่แบบ

ตัวอย่างที่ 1: ฟังก์ชั่นที่รับฟังก์ชั่น

func Apply[T any](f func(T) T, x T) T {
  return f(x)
}

func pure(x int) int {
  return x * 2
}

func TestApply() {
  result := Apply(pure, 5)
  println(result) // Output: 10
}

ตรงนี้มีเรื่องน่าสนใจคือ เราสามารถเอาฟังก์ชั่นไปใส่ไว้ในตัวแปรไว้ก่อนได้ไหมแล้วค่อยส่งไปใน function ที่รับ function

ตัวอย่างที่ 2: ตัวแปรที่เป็นฟังก์ชั่น


func TestApply() {
  double :=  func (x int) int {
    return x * 2
  }
  
  result := Apply(double, 5)
  println(result)
}

ถึงตรงนี้เราเริ่มเห็นอะไรน่าสนุกละ

ตัวอย่างที่ 3 ฟังก์ชั่นที่รับฟังก์ชั่นเข้ามาแล้ว return ฟังก์ชั่นกลับออกไป

// Example 2: A higher-order function that returns a function
func Compose[T any](f, g func(T) T) func(T) T {
	return func(x T) T {
		fmt.Println("Composing functions!!!")
		return f(g(x))
	}
}

func TestCompose() {
	double := func(x int) int {
		fmt.Println("Doubling!!!")
		return x * 2
	}
	increment := func(x int) int {
		fmt.Println("Incrementing!!!")
		return x + 1
	}
	composed := Compose(double, increment)
	result := composed
	fmt.Println(result)// 0xa6210
	fmt.Println(result(5))//Output: 12 (double(increment(5)) = double(6) = 12)
}

สำหรับผมจุดนี้เป็นจุดที่น่าสนใจและเป็นจุดเชื่อมที่สำคัญมาก เราจะเห็นว่า composed เป็นตัวแปรที่มี type เป็น function และใน function ทั้งสองตัวมี effect ที่ถูกทดเอาไว้แต่ยังไม่ทำงานจนกว่าจะจะสั่งให้มันทำงาน !!!!!! และก่อนนั้นเราสามารถ reassign มันไปมาได้ เราจะใช้สิ่งนี้สร้างของที่ ทรงพลังมากในการคิดแบบ functional (ตอนถัดๆไป)

Read more

Tuple: ปรัชญาของการปูเสื่อ และศิลปะแห่งการไม่ตั้งชื่อ

Tuple: ปรัชญาของการปูเสื่อ และศิลปะแห่งการไม่ตั้งชื่อ

ในโลกของการเขียนโปรแกรม เรามักถูกสอนให้เป็น “นักจัดระเบียบ” เราสร้างคลาส สร้าง Struct ตั้งชื่อตัวแปรให้สื่อความหมาย (Clean Code) แต่บางครั้ง ความเคร่งครัดที่มากเกินไปอาจกลายเป็นพันธนาการที่ทำให้ Code ของเราอุ้ยอ้ายโดยไม่จำเป็น 1. Naming Fatigue: ภาระของการมีตัวตน ลองนึกภาพคุณได้

By Santi
The Art of Early Return: วินัยแห่งการ “คัดออก” เพื่อสมองที่โล่งกว่าเดิม 10 เท่า

The Art of Early Return: วินัยแห่งการ “คัดออก” เพื่อสมองที่โล่งกว่าเดิม 10 เท่า

ในโลกของการพัฒนาซอฟต์แวร์ เรามักจะถูกสอนให้เป็นคนรอบคอบ ให้คิดถึงความเป็นไปได้ให้ครบทุกด้าน แต่บ่อยครั้งที่ “ความรอบคอบ” นั้นกลับกลายเป็นกับดักที่สร้างความซับซ้อนจนเราเองก็รับมือไม่ไหว วันนี้ผมอยากจะหยิบยกปรัชญาหนึ่งที่ผมพบจากการเขียนโปรแกรม โดยเฉพาะในภาษาอย่าง Rust ซึ่งมันไม่

By Santi
The Logic Trap: เมื่อ “ความถูกต้อง” กลายเป็นอาวุธที่ทำลายทีมซอฟต์แวร์

The Logic Trap: เมื่อ “ความถูกต้อง” กลายเป็นอาวุธที่ทำลายทีมซอฟต์แวร์

ในโลกของการพัฒนาซอฟต์แวร์ เราถูกสอนให้เทิดทูน Logic เป็นพระเจ้า เราใช้เหตุผลในการคัดเลือก Stack, ใช้ความถูกต้องในการทำ Code Review และใช้ตัวเลขในการวาง Roadmap แต่เคยสงสัยไหมครับ? ทั้งที่เราพูดเรื่องที่ “ถูกต้อง” และเป็น “ความจริง” ทุกประการ ทำไมผลลัพธ์ในห้องประชุ

By Santi
Change Management ต้องทำไหมนะ แล้วทำตอนไหน

Change Management ต้องทำไหมนะ แล้วทำตอนไหน

เนื่องจากช่วงนี้ได้ทำงานกับลูกค้าที่มีการเปลี่ยนแปลงทาง scope ของงานเยอะมาก อารมณ์แบบตอน baseline เป็นแบบนึง พอจะเลือกงานมาทำจริงๆ เรียกว่าเปลี่ยนไปตาม strategy ขององค์กรเลยก็ว่าได้ ในฐานะที่เราเป็นกลุ่มนักพัฒนา ที่ยังจำเป็นต้องควบคุมงบประมาณ กำหนด scope และต้องตอบให้ได้ว่า

By Thanthiya Phatharamalai