ย้ายมาตั้งหลักที่นี่ดีกว่า
คำถามง่ายลงนิด เพื่อให้คนอื่นๆได้เริ่มรู้จัก functional ไปในตัวด้วย
ไม่จำกัด solution เหมือนเดิม (ruby, python, erlang, haskell, ml, scheme, clisp, etc..)
Note: ไปเห็นคำถามนี้ใน mailing list อีกแล้ว
John is a person. His age is 30. Mary is a person, Her age is 25. Find all persons whose age is greater than 28.
กระทู้เก่าๆ จะย้ายตามไปในภายหลัง ตอนนี้ปิดการโพสต์กระทู้ไว้ เหลือไว้เฉพาะอ้างอิงเท่านั้น
งงโจทย์อ่ะครับ?
งงเหมือนกัน
ลองดู solution ที่เขียนด้วย clisp ครับ
ของ Python http://www.codenone.com/node/66 อืมเริ่มจะเข้าใจมากขึ้น มันไม่มี loop จริงๆ ด้วย รอดูแบบ Ruby ดีกว่า
ลอง Lua มั่ง
Person = {} mt = {} function Person:new(name, age) return setmetatable({name = name, age = age}, mt) end function map(func, array) local new_array = {} for i,v in ipairs(array) do new_array[i] = func(v) end return new_array end function solve(persons) return map(function(p) if p.age < 28 then print(string.format('Name: %s, Age: %d\n',p.name,p.age)) end end, persons) end persons = { Person:new('John',30), Person:new('Mary',25) } solve(persons)คุณสุกรี ช่วยอธิบาย setmetatable ได้ไหมครับ
ว่ามันคืออะไร
แฮ่ะๆ ผมก็พึ่งเขียน Lua ครั้งแรกเหมือนกัน
setmetatable()มีไว้ใช้สำหรับจำลองความสามารถของ class ครับ เพราะ Lua ไม่มี class และไม่มีวันมีด้วย แต่เราสามารถจำลองการทำงานของ class ได้บางอย่าง ไม่สมบูรณ์นัก แต่ก็ได้หลักการพอสมควร หนึ่งในนั้นคือ class ละ เนื่องจากโค้ดนี้ไม่ได้มี method อะไรเลยซักอย่าง มันก็ไม่จำเป็นต้องใช้setmetatable()ผมก็ใส่ไปเพื่อให้เคยชินเท่านั้นเอง แค่ข้างล่างนี่ก็พอfunction Person:new(name, age) return {name = name, age = age} endส่วน
setmetatable()ต้องแบบนี้function map(func, array) local new_array = {} for i,v in ipairs(array) do new_array[i] = func(v) end return new_array end Person = {} mt = {} function Person:new(name, age) return setmetatable({name = name, age = age}, mt) end function Person:print() print(string.format('name: %s, Age: %d\n',self.name,self.age)) end mt.__index = Person function solve(persons) return map(function(p) if p.age < 28 then p:print() end end, persons) end persons = { Person:new('John',30), Person:new('Mary',25) } solve(persons)จริงๆ โค้ดอันแรกมันตกไปบรรทัดนึง พอดีไม่ได้ใช้อยู่แล้วเลยรอดมาได้
mt.__index = Personเอาไว้บอกว่ามี method อะไรใน
Personบ้างพอต้องพิมพ์ผลลัพธ์แล้วมันจะเศร้า่ ๆ อ่ะครับ (แบบ มันจะเขียนแล้วแหม่งๆ) ก็เลยคืนลิสต์มา แล้วเอามาพิมพ์อีกที
บน ML นะครับ
(* return all elements x such that g(x) is true *) fun findall([],_) = [] | findall(x::xs,g) = if g(x) then x::findall(xs,g) else findall(xs,g); datatype person = PERSON of string * int; val persons = [PERSON("Jonh",30),PERSON("Mary",25)]; fun printpersonlist([]) = () | printpersonlist(PERSON(n,a)::xs) = (print("Name: " ^ n ^ ", age: " ^ Int.toString(a) ^ "\n"); printpersonlist(xs)); printpersonlist(findall(persons, fn PERSON(_,age) => age>28));แยกแล้วดีกว่ากันเยอะครับ
ตอนเขียน clisp จริงๆก็เขียนแยกได้
แต่ขี้เกียจไปหน่อย ก็เลยเรียงกันอยู่ใน function เดียว
กำลังเริ่มมอง scala อยู่
เพราะมัน run บน java vm ได้
class Person(_name: String, _age: int) { def name = _name def age = _age override def toString(): String = { "name: " + name + ", age:" + age; } } object Cn2 { def main(args : Array[String]) : Unit = { var ps = new Array[Person](2); ps(0) = new Person("Jonh", 30); ps(1) = new Person("Marry", 25); var results = ps.filter(person => person.age > 28); results.foreach(person => System.out.println(person)); } }อืมม์ ถึงจะเป็น functional แล้ว แต่ก็รู้สึกว่ามันยาวอยู่ดี
โดยเฉพาะส่วน array
(อาจจะมีวิธี construct array ที่ดีกว่านี้ แต่ผมยังไม่รู้วิธี)
อืมม์รู้วิธี construct array แล้ว
object Codenone2 { case class Person(name: String, age: Int); val people = List(Person("John", 30), Person("Marry", 25)) def main(args : Array[String]) : Unit = { val ps = people.filter(person => person.age > 28); for(val p <- ps) Console.println(p); } }ของ ruby ครับ
Lua อีกแบบนึง
function map(func, array) local new_array = {} for i,v in ipairs(array) do new_array[i] = func(v) end return new_array end function filter(func, array) local ret = {} for k,v in ipairs(array) do if func(v) then table.insert(ret, v) end end return ret end Person = {} function Person:new(name, age) o = {name = name, age = age} setmetatable(o, self) self.__index = self return o end function Person:tostring() return string.format('Name: %s, Age: %d', self.name, self.age) end function solve(persons) ret = filter(function(p) return p.age < 28 end, persons) map(function(p) print(p:tostring()) end, ret) end persons = { Person:new('John', 30), Person:new('Mary', 25) } solve(persons)มันไม่มีอะไรมาให้เลยนี่หว่า ถึงว่าเล็กนัก
ใช้ prototype.js นะครับ อ่านๆ ไปมีแต่ function กับ return
ครั้งแรกที่ผมมีความสุขในการเขียน javascript เกิดขึ้นเมื่ออ่านคู่มือ Lua
เมื่อก่อนไม่ชอบ javascript เลย
เดี๋ยวนี้มันเริ่มสวยวันสวยคืน
ส่ง Python เข้าประกวดบ้าง อืมงานนี้ใครมี
filter()ก็สบายไป ต้องใช้ยาให้ถูกโรค แล้วทำไม Lua มันไม่มีละเนี่ยLua มันเน้นเล็กปะครับ เลยไม่มี
ของ Javascript ก็ใช้ Prototype.js เอา อาจจะต้องทำของ Lua มั่ง
caml
open List;; type person = {name: string; age: int};; let cnex2 persons age = let select_person ans p = if p.age > age then p :: ans else ans in fold_left select_person [] persons ;; cnex2 [{name="John"; age=30}; {name="Mary"; age=25}] 28;;Camelia มันก็พอใช้ได้นะ แต่ว่าสงสัยลง mode ของ Emacs ท่าจะคล่องกว่า
DrScheme
(define-struct person (name age)) (define (cnex2 persons age) (foldl (lambda (p ans) (cond [(> (person-age p) age) (cons p ans)] [else ans])) empty persons)) (cnex2 (list (make-person "John" 30) (make-person "Mary" 25)) 28)เลียนแบบ แต่เปลี่ยน foldl เป็น filter
ruby
Note: ขี้เกียจ print output สวยๆแล้ว
เปลี่ยน style การ construct object ของข้างบน
ท่านี้่เปิดโลกทรรศดี :-)
haskell
data Person = Person {name::String, age::Integer} deriving Show people = [Person {name="John", age=30}, Person {name="Marry", age=25}] solve = filter (\Person {age=x} -> x > 28) peopleNote: ชอบตรง pattern matching ใน lambda ที่ส่งให้ filter
ตรง deriving Show นี่ เราต้องเขียนด้วยเปล่าครับ?
ไม่รู้เข้าใจคำถามอาจารย์มะนาวหรือเปล่านะครับ
กรณีถ้าถามว่า ไม่มีบรรทัด deriving Show ได้หรือไม่
คำตอบคือ ได้
เพราะ deriving Show ไม่มีผลต่อ logic
แต่มีผลในการแสดงผลบน console เรา
สมมติถ้าเอาออก ผมจะไม่สามารถ print ดูบน console ได้
แต่ถ้าเป็นคำถามว่า datatype เรา derive มาจาก Show แล้ว
เราต้อง implement ให้มันรู้ไหมว่า มันต้อง print format ไหนอย่างไร
อืมม์ อันนี้ผมยังไม่รู้กลไกหรือกฎเกณฑ์ของมันเหมือนกัน
แต่เห็นว่าใส่แค่นี้ มันก็ print ออกมาสวยทุกที
หมายถึงอันหลังอ่ะครับ เพราะว่าไม่เห็นเขียนส่วน print แต่แค่ deriving Show มา ก็เลยงงว่ามัน print ให้ได้ด้วยเหรออ่ะครับ... แต่เอ เก่งดีนะเนี่ยะ
erlang
-module(cn2). -export([solve/0]). -record(person, {name, age}). solve() -> People = [#person{name="John", age=30}, #person{name="Marry", age=25}], [P || #person{age=Age} = P <- People, Age > 28].ใช้ prolog ได้เปล่า?
เสร็จแล้ว (โคตรโกง) เวลาค้นก็สั่ง
person(X),age(X,Y),Y>28.ที่ prompt ของโปรล็อก มันจะหา X กับ Y ที่สอดคล้องมาให้ (จะหาให้ทั้งหมด ถ้ากด ';')
หรือถ้าอยากจะเขียนเพร็ดดิเคทหา ก็เขียนได้เป็น
find(X) :- person(X),age(X,Y),Y>28.อ๊าก ลมปราณย้อนกลับ
เจ๋ง
โอ้ ลืมนึกถึง prolog ไปเลย
แต่ว่ามันง่ายจริงๆ
John is a person. His age is 30.
Mary is a person, Her age is 25.
Find all persons whose age is greater than 28.
จอห์นเป็นคนๆนึง เขาอายุ 30
แมรี่เป็นคนๆนึง เธออายุ 25
หาคนทั้งหมดที่อายุมากกว่า 28
เอ:
เขียนสดๆมะกี้นี้เอง อาจจะผิด