Functional Programming
Programming paradigms Imperative Objected-oriented Functional logic Procedural programming Non-procedural programming Or Declarative programming
Procedural programming วิธีการสั่งงานได้รับอิทธิพลโดยตรงจากสถาปัตยกรรมของคอมพิวเตอร์ Von Neumann machine ประกอบดว้ย หน่วยประมวลผลกลาง ควบคุมและประมวลผลคำสั่ง หน่วยความจำ เก็บชุดคำสั่งของโปรแกรมและข้อมูลที่จะใช้ ใช้แนวคิดในการเปลี่ยนสถานะ (ค่าในหน่วยความจำ) ของเครื่องไปตามลำดับ จนได้ผลลัพธ์ที่ต้องการ มักใช้คำสั่งกำหนดค่า (assignment statement) เป็นหลัก ในการควบคุมการทำงาน มีคำสั่งประเภทอื่นๆ ประกอบในการกำหนดลำดับการทำงาน เช่น คำสั่งวนซ้ำ คำสั่งแบบมีเงื่อนไข
Program Modulo Read M1 Read M2 M1 = M1 - M2 If M1 >= 0 then goto (3) M1 = M1 + M2 Write M1 halt
สถานะของคอมพิวเตอร์ขณะประมวลผลโปรแกรม Modulo ลำดับการประมวลผลคำสั่ง (Thread) สถานะของคอมพิวเตอร์ (State) ข้อมูลเข้า ตำแหน่งในหน่วยความจำ ผลลัพธ์ M1 M2 13, 4 (1) read M1 13 (2) read M2 4 (3) M1 = M1-M2 9 (4) If M1 >= 0 goto (3)
Non-procedural programming ออกแบบเพื่อลดอิทธิพลของลักษณะการทำงานของเครื่อง การเขียนโปรแกรมเป็นอิสระจากฮาร์ดแวร์ ภาษาเชิงหน้าที่ ใช้ฟังก์ชั่นที่คล้ายกับฟังก์ชั่นทางคณิตศาสตร์ ระบุการเชื่อมโยงค่าจากข้อมูลเข้าไปยังผลลัพท์ ไม่ต้องระบุขั้นตอนการเปลี่ยนแปลงสถานะภายในเครื่อง ภาษาเชิงตรรกะ ใช้ความสัมพันธ์เป็นส่วนประกอบหลักในการเขียนโปรแกรม เป็นการพิสูจน์ความจริงของความสัมพันธ์ทั้งหลายที่ระบุไว้ ไม่ต้องระบุลำดับการทำงานให้กับโปรแกรม
Functional programming ส่วนประกอบที่สำคัญ โครงสร้างข้อมูลพื้นฐาน คือ ลิสต์ (list) ฟังก์ชั่นพื้นฐาน โครงสร้างที่ใช้สร้างฟังก์ชั่นจากฟังก์ชั่นที่มีอยู่ โปรแกรมประกอบด้วยฟังก์ชั่น นิยามจากนิพจน์ (expression) ค่าเดี่ยว นิพจน์ย่อย นิพจน์แบบมีเงื่อนไข
Imperative vs. Functional int fact(int n) { int i = 1; for (int j = n; j>1; --j) i = i * j; return I; } fun fact(0) = 1 | fact (n) = n * fact(n-1); ไม่มีคำสั่ง (statement) ประกอบด้วยนิพจน์ สั่งให้ทำซ้ำโดยใช้ recursive function เรียกใช้ฟังก์ชั่นให้ทำงาน แทนการระบุในรูปคำสั่ง เช่น fact(3)
การประมวลผล กลไกพื้นฐาน 2 ประการ การเชื่อมโยงระหว่างชื่อกับค่า (binding) การเรียกใช้ฟังก์ชั่น (application) fact(3) เชื่อมโยง 3 กับชื่อ n ในโปรแกรม เรียกใช้ฟังก์ชั่นที่ n มีค่าเป็น 3
ฟังก์ชัน (Function) การเชื่อมโยงข้อมูลจากเซตของโดเมน ไปยัง ข้อมูลในเซตของเรนจ์ (โคโดเมน)
การเชื่อมโยงข้อมูล (Mapping) Total function การเชื่อมโยงข้อมูลทุกตัวในเซตของโดเมน Partial function การเชื่อมโยงข้อมูลบางตัวในเซตของโดเมน ข้อมูลหนึ่งตัวจากเซตของโดเมนจะเชื่อมโยงไปยังข้อมูลเพียงตัวเดียวในเซตของเรนจ์ การนิยามฟังก์ชั่นไม่กำกวม
การอธิบายการเชื่อมโยง การแจกแจงทุกการเชื่อมโยง แผนภาพ กฏหรือสมการ Format and actual parameters
แคลคูลัสแลมป์ดา (Lambda calculus) แคลคูลัสอย่างง่าย ใช้เป็นโมเดลอธิบายการทำงานของฟังก์ชั่น เป็นพื้นฐานในการออกแบบภาษาเชิงหน้าที่ ใช้เครื่องหมาย l (lambda) แทนฟังก์ชั่น ตัวอย่างการนิยามฟังก์ชั่น lx.x*x การเรียกใช้ ((lx.x*x )2)
นิพจน์แลมป์ดา นิพจน์ในแคลคูลัสแลมป์ดามีอยู่ 3 ประเภทคือ ตัวระบุ หรือตัวแปรเดี่ยว (single identifier) นิยามฟังก์ชัน (function definition, or abstraction) (lx. M) การเรียกมใช้ฟังก์ชัน (function application) เขียนอยู่ในรูป MN ((lx. X*x)2) ตัวอย่างนิพจน์แลมป์ดา x (lx. x) ((lx. x) (ly. y))
นิพจน์แลมป์ดา อาจละเว้นวงเล็บได้ มีลำดับจากซ้ายไปขวา Alonzo Church สร้างแคลคูลัสแลมป์ดาขึ้นมาให้คำนวณฟังก์ชันที่มีพารามิเตอร์ตัวเดียว เช่น (lx. x*x) Haskell B. Curry ฟังก์ชันหลายพารามิเตอร์ Currying technique f(x, y) = x*y => (lx. (ly. x*y)) หรือ (lx. (ly. X*y)) 2 => (ly. 2*y)
การคำนวณค่านิพจน์แลมป์ดา วิธีการแปลงรูปนิพจน์ (rewrite) จนได้รูปแบบปกติ (normal form) ((ly. (lx. xyz)a)b) => แม้ใช้ลำดับที่ต่างกันในการ rewrite แต่ผลลัพธ์นำไปสู่รูปแบบปกติที่เหมือนกัน ซึ่งคุณสมบัติการมีรูปแบบเดียวข แงแคลคูลัสแลมป์ดา เรียกว่า มีคุณสมบัติตามทฤษฎีของเชิร์ชและรอสเซอร์ (Church-Rosser theorem) การคำนวณค่านิพจน์แลมป์ดาจะกระทำตามกฏการแปลงรูปนิพจน์ (rewrite rules) หรือบางครั้งเรียกว่า กฏ การลดรูปนิพจน์ (reduction rules) -conversion -reduction
การแปลงแบบอัลฟ่า (-conversion) lx. M => ly. {y/x} M, y is not free in M ถ้า x เป็น bond parameter เราสามารถเปลี่ยนชื่อตัวแปร x เป็น y แต่ทั้งนี้ ชื่อ y จะต้องไม่ปรากฏเป็นตัวแปรอิสระใน M สัญลักษณ์ {y/x} หมายถึงการแทนชื่อ x ด้วย y ตัวอย่าง (lxyz. xz(yz)) (lx. x) (lx. x) => (lxyz. xz(yz)) (lu. u) (lv. v)
การลดรูปแบบเบต้า (-reduction) lx. M => {N/x} M จาก (lxyz. xz(yz)) (lu. u) (lv. v) => (lxyz. xz(yz)) (lu. u) (lv. v) => (lyz. (lu. u)z(yz)) (lv. v) => (lz. (lu. u)z((lv. v)z)) => (lz. (lu. u)z(z)) => (lz. (z) (z)) => (lz. zz)