Skip to content

Functional Programming

แนวคิดหลัก

Pure Functions: ฟังก์ชันที่ไม่มีผลข้างเคียง (side effects) และให้ผลลัพธ์เดียวกันเสมอเมื่อรับอินพุตเดียวกัน

javascript
// Pure function
function add(a, b) {
  return a + b;
}

// Impure function (has side effect)
let total = 0;
function addToTotal(value) {
  total += value; // modifies external state
  return total;
}
rust
// Pure function
fn add(a: i32, b: i32) -> i32 {
  a + b
}

// Impure function (has side effect)
static mut TOTAL: i32 = 0;
fn add_to_total(value: i32) -> i32 {
  unsafe {
    TOTAL += value; // modifies external state
    TOTAL
  }
}
python
# Pure function
def add(a, b):
  return a + b

# Impure function (has side effect)
total = 0
def add_to_total(value):
  global total
  total += value  # modifies external state
  return total
go
package main

// Pure function
func add(a, b int) int {
  return a + b
}

// Impure function (has side effect)
var total = 0
func addToTotal(value int) int {
  total += value // modifies external state
  return total
}

Immutability: ข้อมูลไม่สามารถเปลี่ยนแปลงได้หลังจากสร้างขึ้น ต้องสร้างข้อมูลใหม่แทนการแก้ไข

javascript
// Immutable approach
const originalArray = [1, 2, 3];
const newArray = [...originalArray, 4]; // creates new array

// Mutable approach (avoid in functional programming)
const array = [1, 2, 3];
array.push(4); // modifies original array
rust
// Immutable approach
fn main() {
  let original_vec = vec![1, 2, 3];
  let new_vec = [&original_vec[..], &[4]].concat(); // creates new vector
  
  // Mutable approach (avoid in functional programming)
  let mut vec = vec![1, 2, 3];
  vec.push(4); // modifies original vector
}
python
# Immutable approach
original_list = [1, 2, 3]
new_list = original_list + [4]  # creates new list

# Mutable approach (avoid in functional programming)
my_list = [1, 2, 3]
my_list.append(4)  # modifies original list
go
package main

// Immutable approach
func main() {
  originalSlice := []int{1, 2, 3}
  newSlice := append([]int{}, originalSlice...) // copy slice
  newSlice = append(newSlice, 4)                // append to copy
  
  // Mutable approach (avoid in functional programming)
  slice := []int{1, 2, 3}
  slice = append(slice, 4) // modifies original if capacity allows
}

Higher-Order Functions: ฟังก์ชันที่รับฟังก์ชันเป็นอาร์กิวเมนต์หรือคืนค่าเป็นฟังก์ชัน

javascript
// Function that takes a function as argument
const map = (array, fn) => array.map(fn);
const double = x => x * 2;
console.log(map([1, 2, 3], double)); // [2, 4, 6]

// Function that returns a function
const multiply = x => y => x * y;
const triple = multiply(3);
console.log(triple(4)); // 12
rust
// Function that takes a function as argument
fn map<F>(array: &[i32], f: F) -> Vec<i32> 
where F: Fn(i32) -> i32 
{
  array.iter().map(|&x| f(x)).collect()
}

fn main() {
  let double = |x| x * 2;
  println!("{:?}", map(&[1, 2, 3], double)); // [2, 4, 6]
  
  // Function that returns a function
  fn multiply(x: i32) -> impl Fn(i32) -> i32 {
    move |y| x * y
  }
  
  let triple = multiply(3);
  println!("{}", triple(4)); // 12
}
python
# Function that takes a function as argument
def map_values(array, fn):
  return [fn(x) for x in array]
  
double = lambda x: x * 2
print(map_values([1, 2, 3], double))  # [2, 4, 6]

# Function that returns a function
def multiply(x):
  def inner(y):
    return x * y
  return inner
  
triple = multiply(3)
print(triple(4))  # 12
go
package main

import "fmt"

// Function that takes a function as argument
func mapValues(array []int, fn func(int) int) []int {
  result := make([]int, len(array))
  for i, v := range array {
    result[i] = fn(v)
  }
  return result
}

func main() {
  double := func(x int) int { return x * 2 }
  fmt.Println(mapValues([]int{1, 2, 3}, double)) // [2, 4, 6]
  
  // Function that returns a function
  multiply := func(x int) func(int) int {
    return func(y int) int {
      return x * y
    }
  }
  
  triple := multiply(3)
  fmt.Println(triple(4)) // 12
}

Function Composition: การรวมฟังก์ชันหลายตัวเข้าด้วยกันเพื่อสร้างฟังก์ชันใหม่

javascript
// Simple composition
const compose = (f, g) => x => f(g(x));

const addOne = x => x + 1;
const double = x => x * 2;
const doubleAndAddOne = compose(addOne, double);

console.log(doubleAndAddOne(3)); // 3 * 2 + 1 = 7
rust
// Simple composition
fn compose<F, G, T>(f: F, g: G) -> impl Fn(T) -> T
where
  F: Fn(T) -> T,
  G: Fn(T) -> T,
  T: Copy,
{
  move |x| f(g(x))
}

fn main() {
  let add_one = |x| x + 1;
  let double = |x| x * 2;
  let double_and_add_one = compose(add_one, double);
  
  println!("{}", double_and_add_one(3)); // 3 * 2 + 1 = 7
}
python
# Simple composition
def compose(f, g):
  return lambda x: f(g(x))

add_one = lambda x: x + 1
double = lambda x: x * 2
double_and_add_one = compose(add_one, double)

print(double_and_add_one(3))  # 3 * 2 + 1 = 7
go
package main

import "fmt"

// Simple composition
func compose(f func(int) int, g func(int) int) func(int) int {
  return func(x int) int {
    return f(g(x))
  }
}

func main() {
  addOne := func(x int) int { return x + 1 }
  double := func(x int) int { return x * 2 }
  doubleAndAddOne := compose(addOne, double)
  
  fmt.Println(doubleAndAddOne(3)) // 3 * 2 + 1 = 7
}

Recursion: การเรียกฟังก์ชันตัวเองซ้ำๆ แทนการใช้ลูป

javascript
// Recursive factorial function
function factorial(n) {
  if (n <= 1) return 1;
  return n * factorial(n - 1);
}

console.log(factorial(5)); // 120

// Instead of imperative loop:
// function factorial(n) {
//   let result = 1;
//   for (let i = 2; i <= n; i++) {
//     result *= i;
//   }
//   return result;
// }
rust
// Recursive factorial function
fn factorial(n: u64) -> u64 {
  if n <= 1 {
    return 1;
  }
  n * factorial(n - 1)
}

fn main() {
  println!("{}", factorial(5)); // 120
  
  // Instead of imperative loop:
  // fn factorial(n: u64) -> u64 {
  //   let mut result = 1;
  //   for i in 2..=n {
  //     result *= i;
  //   }
  //   result
  // }
}
python
# Recursive factorial function
def factorial(n):
  if n <= 1:
    return 1
  return n * factorial(n - 1)

print(factorial(5))  # 120

# Instead of imperative loop:
# def factorial(n):
#   result = 1
#   for i in range(2, n + 1):
#     result *= i
#   return result
go
package main

import "fmt"

// Recursive factorial function
func factorial(n uint64) uint64 {
  if n <= 1 {
    return 1
  }
  return n * factorial(n-1)
}

func main() {
  fmt.Println(factorial(5)) // 120
  
  // Instead of imperative loop:
  // func factorial(n uint64) uint64 {
  //   result := uint64(1)
  //   for i := uint64(2); i <= n; i++ {
  //     result *= i
  //   }
  //   return result
  // }
}

เหมาะสำหรับ

  • การประมวลผลข้อมูลแบบขนาน (Parallel Processing)
  • การจัดการกับโครงสร้างข้อมูลขนาดใหญ่
  • ระบบที่ต้องการความน่าเชื่อถือและทดสอบง่าย
  • การพัฒนาซอฟต์แวร์ที่ซับซ้อนและต้องการบำรุงรักษาในระยะยาว
  • ระบบที่ต้องการความปลอดภัยสูงและลดข้อผิดพลาด