ทำโจทย์กันเถิด #2 (beginner quiz)

ย้ายมาตั้งหลักที่นี่ดีกว่า
คำถามง่ายลงนิด เพื่อให้คนอื่นๆได้เริ่มรู้จัก 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.

งงโจทย์อ่ะครับ?

veer's picture

งงเหมือนกัน

ลองดู solution ที่เขียนด้วย clisp ครับ

(defclass person ()  
  ((name :accessor name :initarg :name)
   (age :accessor age :initarg :age)))
 
(setf persons 
  (list
   (make-instance 'person :name "John" :age 30)
   (make-instance 'person :name "Mary" :age 25)))
 
(defun solve ()
  (mapcar #'(lambda (person)
	      (format t "Name:~a, Age:~a"
		      (name person)
		      (age person))) 
	  (remove-if #'(lambda (person)
			 (<= (age person) 28)) persons)))
sugree's picture

ของ Python http://www.codenone.com/node/66 อืมเริ่มจะเข้าใจมากขึ้น มันไม่มี loop จริงๆ ด้วย รอดูแบบ Ruby ดีกว่า

sugree's picture

ลอง 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 ได้ไหมครับ
ว่ามันคืออะไร

sugree's picture

แฮ่ะๆ ผมก็พึ่งเขียน 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);
  }
}
elixer's picture

ของ ruby ครับ

	def solve persons
		persons.each do |person, age|
  			if age > 28 
 			puts person
			end
		end
	end
 
persons = {}
persons['John'] = 30
persons['Mary'] = 25
 
solve persons
sugree's picture

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)

มันไม่มีอะไรมาให้เลยนี่หว่า ถึงว่าเล็กนัก

veer's picture

ใช้ prototype.js นะครับ อ่านๆ ไปมีแต่ function กับ return

function Person(name, age) {
    return {name: name, age: age};
}
function cnex2(persons, age) {
    return $A(persons).select(function(person) {
        return person.age > age;
    })
}
cnex2([new Person("John", 30), new Person("Mary", 25)]);

ครั้งแรกที่ผมมีความสุขในการเขียน javascript เกิดขึ้นเมื่ออ่านคู่มือ Lua

เมื่อก่อนไม่ชอบ javascript เลย
เดี๋ยวนี้มันเริ่มสวยวันสวยคืน

sugree's picture
solve_3 = lambda ps: filter(lambda p: p[1] < 28,ps.items())
 
persons = {'John': 30,
           'Mary': 25}
 
print '\n'.join(map(lambda p: 'Name: %s, Age: %s' % p,solve_3(persons)))

ส่ง Python เข้าประกวดบ้าง อืมงานนี้ใครมี filter() ก็สบายไป ต้องใช้ยาให้ถูกโรค แล้วทำไม Lua มันไม่มีละเนี่ย

veer's picture

Lua มันเน้นเล็กปะครับ เลยไม่มี
ของ Javascript ก็ใช้ Prototype.js เอา อาจจะต้องทำของ Lua มั่ง

veer's picture

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 ท่าจะคล่องกว่า

veer's picture

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

(require (lib "list.ss"))
 
(define-struct person (name age))
 
(define persons
  (list 
   (make-person "Jonh" 30)
   (make-person "Mary" 25)))
 
(define (solve persons)
  (filter (lambda (person) (> (person-age person) 28))
          persons))

ruby

class Person
  attr_accessor :name, :age
  def initialize(name, age)
    @name = name
    @age = age
  end
end
 
persons = []
persons << Person.new("John", 30)
persons << Person.new("Mary", 25)
 
persons.find_all {|person| person.age > 28}

Note: ขี้เกียจ print output สวยๆแล้ว

เปลี่ยน style การ construct object ของข้างบน

class Person
  attr_accessor :name, :age
  def initialize(hash)
    hash.each do |key, value|
      self.send "#{key}=", value
    end
  end
end
 
persons = []
persons << Person.new(:name =>"John", :age => 30)
persons << Person.new(:name =>"Mary", :age => 25)
veer's picture

ท่านี้่เปิดโลกทรรศดี :-)

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) people

Note: ชอบตรง pattern matching ใน lambda ที่ส่งให้ filter

ตรง deriving Show นี่ เราต้องเขียนด้วยเปล่าครับ?

ไม่รู้เข้าใจคำถามอาจารย์มะนาวหรือเปล่านะครับ

กรณีถ้าถามว่า ไม่มีบรรทัด deriving Show ได้หรือไม่
คำตอบคือ ได้
เพราะ deriving Show ไม่มีผลต่อ logic
แต่มีผลในการแสดงผลบน console เรา
สมมติถ้าเอาออก ผมจะไม่สามารถ print ดูบน console ได้

Main> solve
ERROR - Cannot find "show" function for:
*** Expression : solve
*** Of type    : [Person]

Main> 

แต่ถ้าเป็นคำถามว่า 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(john).
person(mary).
 
age(john,30).
age(mary,25).

เสร็จแล้ว (โคตรโกง) เวลาค้นก็สั่ง
person(X),age(X,Y),Y>28.
ที่ prompt ของโปรล็อก มันจะหา X กับ Y ที่สอดคล้องมาให้ (จะหาให้ทั้งหมด ถ้ากด ';')

หรือถ้าอยากจะเขียนเพร็ดดิเคทหา ก็เขียนได้เป็น
find(X) :- person(X),age(X,Y),Y>28.

sugree's picture

อ๊าก ลมปราณย้อนกลับ

veer's picture

เจ๋ง

โอ้ ลืมนึกถึง 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
เอ:

<?php
$person = array("John","Mary");
$age = array("30","25");
while($i=0;$i<=count($person);$i++;){
if($age[$i]>28){
print " ,".$person[$i];
}
}
php?>

เขียนสดๆมะกี้นี้เอง อาจจะผิด

ย้าย Codenone

ประกาศย้าย Codenone ไปใช้ Forum ของ Blognone แทนครับ ตามไปตั้งกระทู้ต่อได้ที่ Codenone Forum (รายละเอียดอ่านจากกระทู้ ย้าย Codenone ไปรวมกับ Blognone)

กระทู้เก่าๆ จะย้ายตามไปในภายหลัง ตอนนี้ปิดการโพสต์กระทู้ไว้ เหลือไว้เฉพาะอ้างอิงเท่านั้น