Saturday, February 04, 2006

define-syntax ใน scheme

เคยพูดถึง DSL (Domain Specific Language) ไปแล้ว
ซึ่ง RoR หยิบมา implement ในหลายๆส่วนใน ActiveRecord
เช่น
  • การ declare relationship ระหว่าง model
  • การ declare Validate rule ของ model


ใน scheme มี function define-syntaxที่อนุญาตให้เรา define syntax ของเราเองได้
ลองดูตัวอย่างง่ายๆ (ง่ายสุดๆ)

ปกติใน scheme, การ assign value ให้กับ variable จะใช้ syntax นี้
(define a 10)


วันดีคืนดี เกิดอยากเปลี่ยนรูปแบบ syntax ให้เป็นแบบนี้
(mylet a = 10)

Note: อยากใช้ let นะ จะได้เหมือน basic แต่ว่า scheme มี let ใช้แล้ว
เลยเปลี่ยนเป็น mylet แทน

วิธี define syntax ก็ง่ายๆ
เริ่มด้วย

(define-syntax mylet
(lambda (x)
(syntax-case x (=)
(
;;pattern to match
(mylet var = value)
;;transformer
(syntax (define var value))
)
)))


เริ่มด้วย (mylet a = 10) จะถูก pass เข้าไปในรูปตัวแปร x
จากนั้นก็จะถูก function syntax-case เอาไปใช้ในการทำ pattern matching

ประโยค syntax-case x (=) หมายความว่า
เครื่องหมาย = ใช้เป็น reserved word สำหรับ syntax นี้

ใน syntax-case จะประกอบด้วย
pattern mathcing กับ transformer

(mylet var = value) เป็น pattern matching
ซึ่งจะถูก match เข้ากับ (mylet a = 10)
ผลลัพท์ที่ได้ var => a, value => 10

(syntax (define var value)) เป็นส่วน transformer
ในที่นี้ (mylet a = 10) ก็จะถูกแปลงเป็น (define a 10)

อ่านตัวอย่างเพิ่มเติมในบทความ Metaprogramming using Scheme

Related link from Roti

Python at Google
At Google, python is one of the 3 "official languages" alongside with C++ and Java. Official here means that Googlers are allowed to deploy these languages to production services.


(Python used by) A few services including code.google.com and google groups. Most other front ends are in C++ (google.com) and Java (gmail). All web services are built on top of a highly optimizing http server wrapped with SWIG.

Note: ข้างบนนั้น ตัดมาเฉพาะส่วนที่มี interactive กันคนภายนอก
use case อื่นๆ ลองอ่านดูในเอกสาร

Related link from Roti

Friday, February 03, 2006

DENIM

DENIM
An Informal Tool For Early Stage Web Site and UI Design
ลองใช้แล้ว work ดี
(มี bug ประปราย)
ถ้ามี tablet ช่วย ก็ิยิ่งดีใหญ่

ตอนแรกนึกว่าช่วย sketch อย่างเดียว
แต่กลายเป็นว่า run ได้อีกต่างหาก



Note: ข้อเสียคือความยากในการเขียนตัวหนังสือให้สวย
ไม่รู้ว่าเป็นความผิดคนเขียน หรือความผิด tablet

Related link from Roti

Wednesday, February 01, 2006

Emacs viper mode

พึ่งรู้ (อีกแล้ว) ว่า emacs มี viper-mode ให้ใช้
(viper-mode ก็คือ vi emulator mode)

เยี่ยม ตอนนี้ผมเลยสามารถใช้ visual mode ใน emacs ได้แล้ว
แถมยังใช้ command สลับกันระหว่าง emacs หรือ vi ก็ได้
เช่น การลบบรรทัด จะใช้ dd หรือ C-k ก็ได้

Related link from Roti

Tuesday, January 31, 2006

Trip จักรยาน ประจำปี 49



ทุกเดือนกุมภาพันธ์ ผมจะมีนัดขี่จักรยานกับพี่ๆที่รู้จัก
ปีนี้เป็นปีที่ 4 แล้ว
ปีแรกเดินทางจาก กรุงเทพฯ ไปอุบล
โดยพยายามยึดเส้นทางว่า ทางด้านขวามือให้เป็นกัมพูชาไว้

ปีที่สอง เอารถจักรยานขึ้นรถทัวร์ไปเริ่มที่อุบลฯ
คราวนี้ยึดหลักว่า พยายามให้แม่น้ำโขงอยู่ด้านขวาไว้
trip นี้ไปจบที่ นครพนม


ปีที่สาม ปีนี้ติดเลี้ยงลูก เลยไม่ได้ไป
พวกพี่ๆเขาปั่นจาก นครพนม ไปจนถึงน่าน

ปีนี้ก็เลยเริ่มต้นกันที่น่าน
แผนหลักๆ ก็คือให้ลาวอยู่ด้านขวาไว้ จนกว่าจะเจอพม่า

พวกผมเรียก Trip แบบนี้ว่า ซำเหมา
เป็นการขี่แบบไม่มีแผน และไม่มีมาด
แผนจะเป็นไปโดยคร่าวๆ เช่น พยายามให้แม่น้ำโขงอยู่ขวานะ
ไม่มีการกำหนดเส้นทาง หรือจุดหมายไว้ก่อน
ระหว่างทาง เห็นอะไรน่าสนใจ ก็แวะ
เช่นรูปนี้แวะซื้อมะเขือเทศกิน


การค้างแรม ก็ใช้หลัก ค่ำไหนนอนนั่น
โรงแรมไม่เคยแวะ
ที่นิยมสุด ก็คือวัด


ส่วนคำว่าไม่มีมาด ก็คือ
ปกติเวลาเราเห็น นักขี่จักรยาน ที่เขาไปขี่กันเป็นกลุ่มๆ
เขาจะมีชุดคับติ้ว สีสวยๆ
จักรยานจะดูสวยและเงางาม

ส่วนของพวกผมจะไม่มีการแต่งแบบนั้น
มีอะไรก็แต่งไป
จักรยาน ก็ใช้จักรยานมือสอง
(ซื้อจากพวกที่เขาขนของเก่าจากญี่ปุ่นมาขาย)

ปีนี้การเดินทางแยกเป็น 2 กลุ่ม
กลุ่มแรกเดินทางตั้งแต่วันที่ 1 กพ. โดยเริ่มต้นขี่จากกรุงเทพฯขึ้นไป
ส่วนกลุ่มที่ 2 ออกเดินทางวันที่ 10 กพ. โดยนั่งรถทัวร์ไปลงที่น่าน

ช่วงนี้ก็เลยเริ่มซ้อมขี่แล้ว
เมื่อใช้แรงเยอะ สมองก็ลดการใช้งานลง
blog ก็คงจะไม่มีแรงเขียน
ไว้กลับมาจากเหนือแล้วค่อยเริ่มเขียนใหม่



ปล. คุณ poonlap สนใจไหม?

Related link from Roti

มีเสน่ห์ดี
Lotte Klaver

Related link from Roti

Sunday, January 29, 2006

ใช้ emacs ช่วยทำ syntax highlight สำหรับ code ที่แสดงใน blog

เมื่อก่อนผมใช้วิธีเขียน jedit plugin สำหรับ generate syntax highlight


ปัจจุบัน หลังจากเปลี่ยนมาใช้ emacs แล้ว
ก็เลยเปลี่ยนวิธีด้วย
หันมาใช้ htmlize แทน

แต่ก็ยังไม่ค่อยสะดวกอยู่ตรงที่
เนื่องจาก htmlize มัน generate เป็น html เต็มๆให้เลย
ก็เลยต้องใช้ mouse คอยลากเฉพาะบริเวณที่ต้องการอีกที

วันนี้ หลังจากเริ่มปีกกล้าขาแข็งกับ clisp
ก็เลยลองเขียน elisp ดู

เป็น function ที่ช่วย copy เฉพาะบริเวณที่เราต้องการ ลง clipboard

(defun my-hook ()
(let ((pos_1 (search-forward "<pre>"))
(pos_2 (search-forward "</pre>")))
(kill-region pos_1 (- pos_2 6))
(kill-this-buffer)))

(add-hook 'htmlize-after-hook 'my-hook)


การทำงานก็ง่ายๆ
เริ่มด้วยการ define function my-hook ขึ้นมา
กำหนดให้ pos_1 คือ ตำแหน่งที่มีคำว่า <pre> อยู่
ส่วน pos_2 ก็คือ ตำแหน่งที่มีคำว่า </pre>
จากนั้น ก็ใช้ kill-region เพื่อ copy text ที่อยู่ระหว่าง pos1 กับ pos2 ลง clipboard
จบด้วยการก็ปิด buffer ที่ htmlize เปิด

สุดท้ายก็ add function ของเราลงไปใน hook ที่ htmlize เตรียมไว้ให้

Related link from Roti

ทดลอง Implement Search Library ด้วย clisp, java, ruby

ช่วงนี้กำลังอ่าน Paradigms of Artificial Intelligence Programming อยู่
เล่มนี้เขาเขียนอธิบายดี มี code ประกอบชัดเจน
(ผมเป็นพวกประเภทอ่านหลักการล้วนๆไม่ได้ ต้องเห็น code จึงจะเข้าใจ)
code ที่เขาใช้ก็คือ clisp
เห็นวิธีเขียน code เขาแล้ว
คนที่มี background java อย่างผม ก็เลยอื้งไป (อึ้งเพราะทึ่ง)
ลองดูตัวอย่าง
code นี้คัดมาจาก search.lisp ที่อยู่ใน www.norvig.com (web ของ คนแต่งหนังสือ)
(defconstant fail nil "Indicates pat-match failure")

(defun tree-search (states goal-p successors combiner)
"Find a state that satisfies goal-p. Start with states.
and search according to successors and combiner."

(dbg :search "~&;; Search: ~a" states)
(cond ((null states) fail)
((funcall goal-p (first states)) (first states))
(t (tree-search
(funcall combiner
(funcall successors (first states))
(rest states))
goal-p successors combiner))))

(defun depth-first-search (start goal-p successors)
"Search new sates first until goal is reach."
(tree-search (list start) goal-p successors #'append))

(defun prepend (x y) (append y x))

(defun breadth-first-search (start goal-p successors)
(tree-search (list start) goal-p successors #'prepend))


ลอง implement เป็น java ดู
public abstract class TreeSearch<T> {

IGoalPredicate<T> goalPredicate;
ISuccessor<T> successor;
public static boolean DEBUG = true;

public TreeSearch(IGoalPredicate<T> goalPredicate,
ISuccessor<T> successor) {
this.goalPredicate = goalPredicate;
this.successor = successor;
}

public T search (List<T> states) {

if (states.size() == 0) {
return null;
}

if (DEBUG) {
for (Iterator<T> iter = states.iterator(); iter.hasNext();) {
T element = iter.next();
System.out.print(element + ", ");

}
System.out.println();
}

T curState = states.remove(0);

if (goalPredicate.isGoalState(curState)) {
return curState;
}
return search(
combine(states, successor.createSuccessors(curState)));
}

public abstract List<T> combine (List<T> oldList, List<T> newList);
}

public interface IGoalPredicate<T> {
public boolean isGoalState(T state);
}

public interface ISuccessor<T> {
public List<T> createSuccessors(T state);
}

public class BreadthFirstSearch<T> extends TreeSearch<T> {

public BreadthFirstSearch(IGoalPredicate<T> goalPredicate, ISuccessor<T> successor) {
super(goalPredicate, successor);
}

@Override
public List<T> combine(List<T> oldList, List<T> newList) {
ArrayList<T> list = new ArrayList<T>();
list.addAll(oldList);
list.addAll(newList);
return list;
}

}

ก็ไม่เลวนะ ถ้าเป็นเมื่อก่อนต้องรู้สึก "แหมดูดีจัง"

ลอง implement แบบ ruby บ้าง
ruby implement ได้ 2 แบบ คือ
เป็น object style หรือ standalone method style
เลือกวิธีหลังดีกว่า
module Search
@@debug = false;
require 'pp'

def tree_search(states, goal_p, successors, combiner)

pp states if @@debug

return nil if states.empty?
return states.first if goal_p.call(states.first)

tree_search(combiner.call(successors.call(states.shift), states),
goal_p, successors, combiner)
end

def breadth_first_search(start, goal_p, successors)
combiner = lambda { |x, y| y + x }
tree_search([]<<start, goal_p, successors, combiner)
end

def depth_first_search(start, goal_p, successors)
combiner = lambda { |x, y| x + y }
tree_search([]<<start, goal_p, successors, combiner)
end

end

อืมม์ ruby ก็ใช้ได้ สั้นสู้ lisp ได้เหมือนกัน

เปรียบเทียบ code ที่เรียกใช้ดูบ้าง
โดย search binary tree
เพื่อหา node ที่มีค่า = 12



เริ่มด้วย lisp
(defun is (value) 
#'(lambda (x) (eql x value)))

(defun binary-tree (n)
(list (* 2 n) (+ (* 2 n) 1)))

(breadth-first-search 1 (is 12) #'binary-tree)


ส่วน java ยาวเหมือนเดิม
public static void main(String[] args) {

ISuccessor<Integer> suc = new ISuccessor<Integer>() {

public List<Integer> createSuccessors(Integer state) {
ArrayList<Integer> list = new ArrayList<Integer>();
list.add(2 * state);
list.add(2 * state + 1);
return list;
}

};

IGoalPredicate<Integer> goal_p = new IGoalPredicate<Integer>() {

public boolean isGoalState(Integer state) {
if (state == 12) {
return true;
}
return false;
}

};

BreadthFirstSearch<Integer> bs = new BreadthFirstSearch<Integer>(goal_p, suc);
ArrayList<Integer> start = new ArrayList<Integer>();
start.add(1);
bs.search(start);
}


ของ ruby สั้นดีมาก
include Search
gp = lambda {|state| state == 12}
successors = lambda {|x| [x*2, x*2+1]}
breadth_first_search(1, gp, successors)



การเรียน lisp ก็ดีอย่างหนึ่งนะ
เพราะถ้าเป็นเมื่อก่อน case นี้ ผมคงจะเลือก implmenet แบบ Object Style
(เพราะทำเป็นอยู่แบบเดียว)
แต่พอเริ่มเขียน lisp เป็น
มันก็เลยมีทางเลือกอื่นๆเพิ่มขึ้นมา

Related link from Roti

Fugi

Fugi
board หรือ forum แนวใหม่
layout เจ๋งดี

Note: ใช้ rails เขียน

Related link from Roti