เดิมโพสต์เมื่อ 2015-06-25

ภาษาใหม่ ๆ เดี๋ยวนี้ ทั้ง Rust, Swift, F#, Scala หรือภาษากลางเก่ากลางใหม่แบบ C#, Java 8, Python, Ruby, JavaScript มักจะมีกลิ่นอายของ Lisp/Scheme ติดมาด้วยเสมอเช่นการ ใช้ closure กับ map, foldl, foldr, filter เป็นต้น

เนื่องจากว่าเขียนได้ทั้งแนว Fortran และแนว Lisp เวลาคนเขียนภาษาใหม่ ๆ เช่น Python บางทีก็จะเถียงกัน (ผมเห็นจากใน blog ของคนอื่น) ว่าจะใช้ map filter reduce ทำไม อ่านยากจะแย่ จะเขียนสั้น ๆ ทำไม ต้องใช้ for-loop แทนสิ บางคนก็บอกว่า map filter reduce มันก็ดีอยู่แล้ว เขียน for-loop มันอ่านง่ายตรงไหน

ส่วนภาษา Go เป็นภาษาใหม่ที่เน้น imperative (แนว Fortran) ล้วน ๆ และออกแนว minimalism คำสั่งที่มีมาให้ก็เป็นไปแต่แบบพอเพียง บางอย่างที่เขาคิดว่าไม่จำเป็นเขาก็ไม่มีให้ ทำให้แน่นอนไม่มี map, fold, foldr, filter แถมมาให้ ถ้าอยากได้ก็ต้องทำเองในระดับ library

แน่นอนว่าในระดับ Library นี้ compiler เข้ามาช่วย optimize ให้ได้ยาก พอใช้ไปก็จะทำให้โปรแกรมช้าได้

ด้วย 2 เหตุนี้คือขัดวิถีโกและช้า ทำให้โอกาสที่ใคร ๆ จะเขียนแนว Lisp/Scheme ใน Go มีน้อย

ดังนั้นใครหรือทีมไหนที่ไม่ชอบเขียนโปรแกรมที่มีกลิ่นอายของ Lisp/Scheme ในยุคนี้ภาษา Go เหมาะอย่างยิ่ง

Sometimes a consumer takes a long time to finish a task, and producers keep sending data. This situation can cause a memory leak. Keep processing out-dated data makes no sense in some applications.

So I write a program to keep receiving data within 10ms time frame, and discard old data.

use std::sync::mpsc::channel;
use std::{thread, time};

fn main() {
    let (tx, rx) = channel();
    thread::spawn(move || {
        let tx_delay_time = time::Duration::from_millis(100);
        loop {
            for i in 1..1000 {
                tx.send(i).expect("Cannot send");
                if i % 10 == 0 {

    let timeout = time::Duration::from_millis(10);
    loop {
        let mut i = None;
        loop {
            match rx.recv_timeout(timeout) {
                Ok(j) => {
                    i = Some(j);
                Err(_) => {
                    if i.is_some() {
        // long task ...
        println!("{:?}", i);
        i = None;

I feel that the program look too complicated. Perhaps I shouldn't a channel at all in this case. 🤣

 ;; custom-set-faces was added by Custom.
 ;; If you edit it by hand, you could mess it up, so be careful.
 ;; Your init file should contain only one such instance.
 ;; If there is more than one, they won't work right.
 '(default ((t (:family "Noto Mono" :foundry "GOOG" :slant normal :weight normal :height 128 :width normal))))
 '(rainbow-delimiters-depth-2-face ((t (:inherit rainbow-delimiters-base-face :foreground "SeaGreen3"))))
 '(rainbow-delimiters-depth-3-face ((t (:inherit rainbow-delimiters-base-face :foreground "DeepPink1"))))
 '(rainbow-delimiters-depth-4-face ((t (:inherit rainbow-delimiters-base-face :foreground "SteelBlue1"))))
 '(rainbow-delimiters-depth-5-face ((t (:inherit rainbow-delimiters-base-face :foreground "orange red"))))
 '(rainbow-delimiters-depth-6-face ((t (:inherit rainbow-delimiters-base-face :foreground "DarkGoldenrod1")))))

In this meetup, we

  • Trained new translator by collective translation
  • Learned about roles and job description for each role
  • Learned about a code of conduct
  • Defined our responsibility assignment matrix
  • Defined our onboarding process for new contributors
  • Planned to experiment with translating in cross-checking mode
  • Updated our style guide and move it from old wiki page to GitHub and reformat it to Markdown
  • Planed about meetups and applying Mozilla products and projects in educations
  • Talked about how to improve Pontoon in the way that could help us work faster
  • Identified L10n related bugs, which crucial for Thai speakers

Wannaphong is our new translator. He works mainly on localizing Common Voice website. All Thai speakers in the meetup help him review his translations together at once, to demonstrate how to improve our translations.

We collectively reviewed the translations

Now our community has three roles, i.e., contributor, translator, and manager. In brief, everyone can translate at least by making a suggestion. A translator is supposed to work on reviewing other people's translation too. And a manager should manage to build a healthy community, and communicating between all participants.

Mozilla L10N is one of the most culturally diverse free/libre/open source software projects that coordinate contributors around the world for supporting their local languages. IMO, having a code of conduct, namely Mozilla Community Participation Guidelines is vital for making sure that the community does not discourage any demographic group of people from participating. Mozilla has simplified the Community Participation Guidelines, so it should be easier for us to practice.

We also defined our responsibility assignment matrix, and our onboarding process for new contributors, which is supposed to be published later.

For improving translation quality, we planned to experiment with translating in cross-checking mode on Common Voice project first because at least we have more than two translators working on this project. By having more than one translator, we can suggest the translation and another translator can cross-check by reviewing it. However, for trivial translations, cross-checking by making suggestion instead of translating in one step should be avoided.

We updated our style guide in Thai and put it on GitHub. To avoid editing to many suggested translations and make our translation consistent. The style guide is essential for anyone who wants to contribute.

We were updating the style guide, and defining the onboarding process

To have more participant and make more impact, we plan to invite people to talk about other topics rather than L10n in the meetup. We used to talk about Rust, and it went quite well.

About Pontoon, we agree that it is the best localization platform, which we have ever use. And it can improve even further by retrieving existing translations of terms in a long or short string that we about to translate. Moreover, enabling Pontoon to search only on Thai strings in particular patterns can detect errors, without looking at a translation unit one by one.

We believe that language features are critical for the competitiveness of Firefox and related projects among Thai language speaking users. So, we wish #1423593 and #425915 will get fixed soon.

  • Thank Opendream and @kengggg@twitter for offering the meetup venue for free.
  • Thank Wichai Termwuttipreecha for event planning.
  • Thank Peiying Mo, Delphine Lebédel, and @pompoko35@twitter, Teerapat Taechaiya for planning and organizing.
  • Thank Can Udomcharoenchaikit, Nattapong Ekudomsuk, Thanatip Sriviroonchai, Wannaphong Phatthiyaphaibun, Hassadee Pimsuwan, and Densin Roy. for contributing.

Almost everyone

Vee Satayamas

ผมสงสัยว่าทำไม laptop pc ที่เปิดตัวค.ศ. 2019 ยังใช้ Pentium N5000 ที่เปิดตัวตั้งแต่ค.ศ. 2017 อยู่

Pentium N5000 เปิดตัวค.ศ. 2017 TDP 6W ราคา 161 USD

Pentium 4417U เปิดตัวค.ศ. 2019 TDP 15W ราคา 161 USD

benchmark แบบ multicore แล้ว Pentium N5000 เร็วกว่า จาก spec ราคาเท่ากัน กินไฟน้อยกว่า ยี่ห้อเดียวกัน 🤣

ถ้าใช้ core เดียว Pentium 4417U ดีกว่า อีกอย่างคือใส่ RAM ได้ 32GB มากกว่า Pentium N5000 ที่ใส่ได้แค่ 8GB พอไปดู spec เครื่อง laptop ที่ทำมาขายกันก็ใส่ RAM มาแค่ 4GB ทั้งสองเบอร์

เดี๋ยวนี้ web browser ทำงาน multicore ได้แล้ว Rust compiler ก็ได้ PostgreSQL ก็ได้ โปรแกรมผมเองก็ยังทำได้เลย ก็คิดว่าการที่ยังใช้ N5000 อยู่มันสมเหตุสมผลมาก

  • ช่วงค.ศ. 1996 ผมคิดว่าน่าจะเปลี่ยนไปเขียน Java ได้แล้ว
  • ช่วงค.ศ. 2002 ผมคิดว่าน่าจะเปลี่ยนไปเขียน Ruby ได้แล้ว
  • ช่วงค.ศ. 2017 ผมคิดว่าน่าจะเปลี่ยนไปเขียน Clojure ได้แล้ว

ถ้ามองความเป็นไปในโลก Java กับ Ruby ในยุคที่ผ่านมาก็มีคนเอามาทำเว็บเยอะจริง ๆ เรื่อง Java นี่ใคร ๆ ก็เดาได้ ส่วน Ruby นี่กว่าคนจะใช้เยอะก็ช่วงค.ศ. 2006 แล้ว ผมก็แปลกใจนิดหน่อยว่าในที่สุดก็มีคนใช้เยอะจริง ๆ

ผมเขียนหลายภาษาที่ไม่ได้อยากเขียน ถึงจริง ๆ มันก็ดีนั่นล่ะ เช่น Logo Perl Python Prolog Pascal C C++ Awk JavaScript PHP xBase SQL SPARQL Rust พวกนี้เพราะว่าคนอื่นใช้ หลาย ๆ ภาษาผมก็ยังใช้อยู่ด้วย

ผมลองเขียนนิด ๆ หน่อยแต่ก็ไม่ได้ใช้อะไรจริงจัง ผมอาจจะจริงจังแต่มันไปไม่ถึง และไม่คิดว่าอยากจะเปลี่ยนไปใช้ เช่น Haskell OCaml Lua Erlang Kotlin Crystal Objective-C

ภาษาที่เข้า 2 กลุ่มนั้นไม่ได้คือ Go ซึ่งผมอยากเขียนเอง เคยใช้จริงจังแล้วแต่ก็เลิกไป Common Lisp และ Racket ก็เคยใช้จริงจังอยากเขียนเอง แต่คิดว่าเขียน Clojure แทนก็ได้

เป็นอันนึงที่เลือกนานมากคือสีวงลบของ Emacs ใช้ rainbow-delimiters 😅

 ;; custom-set-faces was added by Custom.
 ;; If you edit it by hand, you could mess it up, so be careful.
 ;; Your init file should contain only one such instance.
 ;; If there is more than one, they won't work right.
 '(default ((t (:family "Noto Mono" :foundry "GOOG" :slant normal :weight normal :height 120 :width normal))))
 '(rainbow-delimiters-depth-2-face ((t (:inherit rainbow-delimiters-base-face :foreground "SeaGreen3"))))
 '(rainbow-delimiters-depth-3-face ((t (:inherit rainbow-delimiters-base-face :foreground "DeepPink1"))))
 '(rainbow-delimiters-depth-4-face ((t (:inherit rainbow-delimiters-base-face :foreground "SteelBlue1"))))
 '(rainbow-delimiters-depth-5-face ((t (:inherit rainbow-delimiters-base-face :foreground "orange red"))))
 '(rainbow-delimiters-depth-6-face ((t (:inherit rainbow-delimiters-base-face :foreground "DarkGoldenrod1")))))

AFAIK Generating UUID and Xid needs the MachineGuid, so I looked around how to obtain it.

And this is the solution, which I'm not sure if it will work on every Windows machine. 😅

use winreg::RegKey;
use winreg::enums::*;
use std::io;

fn main() -> io::Result<()> {
    let hklm = RegKey::predef(HKEY_LOCAL_MACHINE);
    let cur_ver = hklm.open_subkey("SOFTWARE\\Microsoft\\Cryptography")?;
    let guid: String = cur_ver.get_value("MachineGuid")?;
    println!("MachineGuid = {}", guid);


name = "mach_guid"
version = "0.1.0"
authors = ["veer6"]
edition = "2018"

winreg = "0.6"

เอกสารเดี๋ยวนี้อาจจะไม่ได้มาแบบเป็นเล่ม ๆ อย่างเดียว บางคนอาจจะใช้ E-book reading จอ 6 นิ้วอ่าน บางคนอาจจะ print ใส่กระดาษ A4 บางคนอาจจะอ่านใน Tablet บางคนอาจจะอ่านบนจอใหญ่ บางคนอาจจะอ่านในโทรศัพท์มือถือ

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

MS Word มันกึ่ง ๆ ระหว่างจะเน้นเนื้อหา หรือว่าจะเน้นจัดหน้าดี จะเลือกว่าส่วนไหนเป็น heading ก็ได้ แต่นึกอยากจะกำหนด font กำหนดขนาดตัวอักษรของแต่ส่วนเองก็ได้อีก

จะใช้ Word แบบเน้นเนื้อหาก็ได้ โดยการเลือก style แทนที่จะไปจัดเอง แต่พอทำจริง ๆ ส่วนมากออกมา format ไม่เป๊ะ มันมีวิธีหลายแบบที่จะทำให้เอกสารออกมาหน้าตาคล้าย ๆ กัน มอง style ก็ไม่ค่อยจะเห็นชัดเท่าไหร่ ทีนี้เอามาประมวลผล หรือแค่จัดรูปแบบใหม่ให้เหมาะกับ online หรือแม้กระทั่ง ebook reader จอเล็ก ๆ มันจะเละ

มันมีสิ่งที่คิดมาแก้เรื่องนี้หลายตัวเช่น GNU Texinfo มันก็ใช้ได้เอกสารของ GNU Project ทั้งหมดใช้ตัว Texinfo เวลาดูเว็บของ GNU หน้าตามันจะซ้ำ ๆ เบื่อ ๆ หน่อย แต่ก็เป็นวิธีที่ทำเอกสารที่ทำทีเดียว ออกมาได้ทั้ง HTML, Info, man ทำเป็น PDF ก็ได้ ปัญหาของ Texinfo คือกว่าจะเขียนเป็นมันก็ไม่ได้ยาก แต่ก็ยากกว่า Word

อีกตัวคือ Gitbook อันนี้ใช้เขียนหนังสือเป็นเล่ม ๆ ได้เลย แล้วก็เอามาสร้างได้หลาย format คล้าย ๆ กับ GNU Texinfo แต่ว่าใช้ Markdown คนทาง IT เดี๋ยวนี้หลาย ๆ คนก็เขียน Markdown เป็นเลย เป็น format ที่ดูง่ายมาก ๆ บางคนอาจจะบอกว่าเปิด docx ออกมาอ่าน format ข้างในก็ได้เหมือนกัน แต่มันก็อ่านยากกว่า Markdown มาก ๆ แต่ถึง Markdown จะง่ายอย่างไรมันก็ยากกว่าใช้ Word อยู่ดี Gitbook ในเว็บเขามีตัวแก้เอกสารแบบ WYSIWYG มาให้เลย แต่ format มันก็จะเป๊ะอยู่ดี WYSIWYG ของเขาไม่ใช่แบบที่ให้มาเลือก font จัดโน่นจัดนี่เอง แต่พอเป็นตัวหนังสือก็จะเลือกได้ว่าจะเป็น Heading 1, Heading 2, Heading 3 อะไรทำนองนั้นไป

ผมมองว่าแบบ Gitbook นี่ล่ะที่น่าจะเหมาะเพราะ

  1. แยกกันระหว่างเนื้อหาและการจัดหน้า
  2. แก้ไขแบบเห็นเหมือนจริง (WYSIWYG) ได้เลย ทำให้ง่าย
  3. ตรวจ format ง่าย เพราะว่าถึงจะเปิดแบบ Markdown มาก็พอจะอ่านรู้เรื่องเลย ทำให้รู้ว่ามันเก็บอะไรลงไปกันแน่
  4. อีกข้อหนึ่งที่แถมคือเวลาแก้ไขเอกสารด้วยกันหลาย ๆ คนพร้อมกันผ่านเว็บนี่มันสะดวกกว่าการส่งไฟล์กันไปมาเยอะแยะ

ผมว่าเทคโนโลยีมันพร้อมแล้ว เหลือแต่ว่าคนจะอยากเปลี่ยนเมื่อไหร่

update 2019-08-04

ยกตัวอย่างเพิ่มเติมเพื่อให้เห็นภาพว่า markdown มันเพิ่มเพิ่มขนาด font ตรง ๆ ไม่ได้ ต้องไปทำผ่านการสร้าง header ทำให้เวลาเอาไปใช้ไม่ต้องมีตีความว่า TH Sarabun PSK 24 นี่มันคืออะไร เป็น header หรือเปล่า หรือ header ระดับไหน

สมัยที่เรียนหนังสือเขามักจะเอา Fibonacci number มาเป็นตัวอย่างกัน function ก็เป็นงี้ครับ

fib(0) = 0 fib(1) = 1 fib(n) = fib(n-1) + fib(n-2) สำหรับ n มากกว่า 1

ซึ่งเอามาแปลงเป็น Clojure ได้แบบตรงไปตรงมาเลย

(def fib
  (fn [n]
    (if (<= n 1) n
        (+ (fib (- n 1)) (fib (- n 2))))))

ผมลองรันบนเครื่องผมใช้เวลา 4.324 วินาที ซึ่งมันช้าเพราะไปเรียก fib ซ้ำไปซ้ำมา ดูง่าย ๆ fib(4) ก็ไปเรียก fib(3), fib(2) แล้ว fib(3) ก็ไปเรียก fib(2) อีกซ้ำ พอเลขมากก็ซ้ำไปเรื่อย ๆ

จริง ๆ มันมีวิธีหล่อ ๆ เยอะแยะที่จะแก้ปัญหานี้ให้เร็วขึ้น แต่ถ้าเราไม่ต้องหล่อมาแก้แบบดอกเดียวเสร็จก็ใช้ memoize เขียนแบบนี้

(def fib
   (fn [n]
     (if (<= n 1) n
         (+ (fib (- n 1))
            (fib (- n 2)))))))
(println (time (fib 42)))

แก้นิดเดียวเอา memoize มาครอบ function ไว้ มันจะจำ function ที่เคยเรียกไว้แล้วส่งผลกลับมาเลยโดยไม่ต้องไล่ยาว ผลคือโปรแกรมใช้เวลารันเหลือ 0.820 วินาที

จริง ๆ มันจบแล้วล่ะ แต่เขียนให้ดูอีก function แบบใช้ loop

(defn fib [n]
  (loop [i 1 acc0 0 acc1 1]
    (if (< i n)
      (recur (inc i) acc1 (+ acc0 acc1))
(println (time (fib 42)))

อันนี้ใช้เวลาแค่ 0.0976 วินาที แต่ก็จะเห็นได้ว่าโปรแกรมเปลี่ยนไปเยอะ เปลี่ยนวิธีคิดเยอะ memoize นี่มันแทบไม่ต้องคิดต้องเขียนอะไรมากเลย ใส่ไปแล้วได้ผลเลย

ขอบคุณ ที่แนะนำ function time มาครับ