Lua, Fennel และ Yuescript สำหรับ Python โปรแกรมเมอร์

พิมพ์ Hello world!

Python

print("Hello world!")
print("Hello", "world!") # ได้ Hello world!

Lua

การ print ด้วย argument หลายตัวใน Python จะแสดงแยกแต่ละตัวด้วย space แต่ใน Lua จะใช้ tab
print("Hello world!")
print("Hello", "world!") -- ได้ Hello    world!
-- หรือกรณีที่มี argument ตัวเดียวและเป็น string หรือ table สามารถยกเว้นวงเล็บได้
print "Hello world!"

Fennel

(print "Hello world!")
(print "Hello" "world!") ;  ได้ Hello    world!

Yuescript

เหมือน Lua แต่สามารถยกเว้นวงเล็บได้
print "Hello", "world!" -- ได้ Hello    world!
print "Hello world!"

การประกาศตัวแปรและการกำหนดค่า

Python

มีรูปแบบเดียวทั้งประกาศตัวแปรและกำหนดค่าไปพร้อมกัน ตัวแปรที่กำหนดค่าไว้นอกสุดของโปรแกรมจะเป็นตัวแปร global นอกนั้นจะเป็น local
x = 1
a, b, c = 2, 3, 4 # กำหนดค่าทีละหลายตัวแปร
d, e = [1, 2] # สามารถแตกค่าใน list หรือ tuple ให้กับตัวแปรที่มีจำนวนเท่ากันได้
f = g = h = 0 สามารถกำหนดค่าเดียวกันให้ตัวแปรหลายตัว

Lua

ตัวแปรใน Lua จะเป็น global โดยปริยายโดยจะเก็บอยู่ในตัวแปรพิเศษประเภท table ที่ชื่อ _G ถ้าจะให้เป็น local ต้องประกาศด้วย local หน้าชื่อตัวแปร

การประกาศตัวแปร

สามารถกำหนดค่าพร้อมกับประกาศตัวแปรหรือจะแค่ประกาศตัวแปร local เฉยๆ ก็ได้โดยจะมีค่าเป็น nil
local x -- ไม่กำหนดค่า x มีค่าเป็น nil
local y = 2
z = 3 -- ตัวแปร global เท่ากับ _G.z = 3

การกำหนดค่า

x = 1
y, z = x, 5 -- y เก็บค่า 1 และ z เก็บค่า 5

Fennel

การประกาศตัวแปร

กำหนดค่าพร้อมกับประกาศตัวแปรโดยตัวแปรทุกตัวจะเป็น local
(var x 0) ; เทียบได้กับ local x = 0 ใน Lua
(var (y z) (values 2 3)) ; ประกาศและกำหนดค่าทีละหลายตัว

การกำหนดค่า

(set x 1)
(set (y z) (values x 5))

การผูกค่ากับตัวแปร

เป็นการกำหนดค่าถาวรไม่สามารถเปลี่ยนแปลงได้มีสองแบบคือ let กับ local
;; let กำหนดตัวแปรเฉพาะภายในขอบเขตของ let
(let [x 1 y (+ x 1)] ; x=1 y=x+1
  (print (+ x y))) ; พิมพ์ค่า x+y ได้ 3
(print x) ; ไม่มีตัวแปร x นอก let ได้ nil

;; local กำนดตัวแปรเข้าถึงได้จากขอบเขตเดียวกันกับที่ local อยู่
(local (x y) (values 1 2))
(print (+ x y)) ; พิมพ์ค่า x+y ได้ 3
(set x 4) ; error ไม่สามารถแก้ไขค่า x ได้
ถ้าเป็นตัวแปร global สามารถประกาศและกำหนดค่าไปพร้อมกันโดยอ้างถึง table _G
(set _G.x 5) ; หรือ (tset _G "x" 5) หรือ (tset _G :x 5)
(print _G.x) ; ได้ 5
(set _G.x (+ _G.x 1))
(print _G.x) ; ได้ 6

Yuescript

เหมือน Python กำหนดค่าพร้อมกับประกาศตัวแปรโดยตัวแปรทุกตัวจะเป็น local แต่สามารถใช้ local กับ global เพื่อประกาศตัวแปรได้

การประกาศตัวแปร

x = 1 -- x เป็นตัวแปร local มีค่าเป็น 1
local y -- ประกาศตัวแปร y เป็นตัวแปร local
global z -- ประกาศ z เป็นตัวแปร global
local a, b = 2 -- ประกาศตัวแปร a และ b เป็นตัวแปร local และกหนดค่า 2 ให้ a
global c = 4 -- ประกาศตัวแปร c เป็นตัวแปร global และกหนดค่า 4 ให้ c

do
  global * -- กำหนดให้ตัวแปรทุกตัวที่ประกาศในบล๊อกเป็น global
  a, b = 10 -- a และ b เป็น global และกำหนดค่า 10 ให้ a
  local c = 4 -- c เป็นตัวแปร local และกำหนดค่า 4 ให้ c

do
  global ^ -- กำหนดให้ตัวแปรทุกตัวที่ประกาศในบล๊อกและขึ้นต้นด้วยตัวพิมพ์ใหญ่เป็น global
  a, B = 10 -- a เป็น local มีค่าเป็น 10 และ B เป็น global

การกำหนดค่า

y, z = 4, 5

ต่อ string

Python

Python ใช้การบวกระหว่าง string เป็นการรวม string เข้าด้วยกัน
a = "Hello" + " world!"
b = " ".join("Hello", "world!")

Lua

Lua มี operator เฉพาะคือ .. สำหรับการต่อ string
local a = "Hello " .. "world!"
local b = table.concat({"Hello", "world!"}, " ")

Fennel

เนื่องจากเป็นภาษาแนว Lisp ที่เป็น prefix notation จึงสามารถใช้ operator เดียวกับ strings หลายตัว
(var a (.. "Hello" " " "world!"))
(var b (table.concat ["Hello" "world!"] " "))

Yuescript

a = "Hello".." " .. "world!"
b = table.concat {"Hello", "world!"}, " "

แบ่งคำใน string ไปเป็น  array

Python

Python มี list เป็นโครงสร้างข้อมูลแบบเรียงลำดับคล้ายกับ array
a = "Hello world!".split() # a มีค่าเป็น ["Hello", "world!"]

Lua

Lua มี table เป็นโครงสร้างข้อมูลประเภทเดียวสามารถใช้แทน array ได้
Lua ไม่มีฟังก์ชันสำหรับแบ่ง string โดยตรงแต่สามารถใช้ Lua pattern ที่เป็นเหมือน subset ของ regular expression ช่วยในการแบ่ง string ได้ หรือจะใช้มอดูลภายนอกสำหรับการจัดการข้อความที่ซับซ้อนอย่าง LPEG ก็ได้
-- ใช้ Lua pattern
local a, b = {}, {}
-- %s หมายถึง " " หรือช่องว่าง
-- %S หมายถึงตัวอักษรที่ไม่ใช่ " " เหมือนกับ [^%s]
for w in string.gmatch("Hello world!", "%S+") do table.insert(a, w) end

for w in ("Hello world!"):gmatch"[^%s]+" do b[#b+1] = w end
-- a และ b มีค่าเป็น {"Hello", "world!"}
-- กรณีที่รู้จำนวณคำ
local c = {("Hello world!"):match("(%S+)%s(%S+)")}

-- ใช้ LPEG
lpeg = require"lpeg"
C, Ct, P = lpeg.C, lpeg.Ct, lpeg.P
local space = P" "
local word = C((P(1)-space)^1)

local d = lpeg.match(Ct(word*(space*word)^0), "Hello world!")

local e = lpeg.match(Ct(C((1-P" ")^1)*(P" "*C((1-P" ")^1))^0), "Hello world!")
-- d และ e มีค่าเป็น {"Hello", "world!"}

Fennel

มี icollect เป็น macro ที่ทำหน้าที่สร้าง table ใหม่จากข้อมูลใน iterator ที่กำหนดคล้ายกับ list comprehension ใน Python

(var a [])
(each [w (string.gmatch "Hello world!" "%w+")] (table.insert a w))

(var b (icollect [w (string.gmatch "Hello world!" "%S+")] w)) ; เหมือน list comprehension

Yuescript

Yuescript มี list/table comprehension คล้ายกับ list/dict comprehension ใน Python
การเรียก method ใน Moonscript ใช้ \ แทน : ใน Lua แต่ Yuescript เพิ่ม :: มาสามารถใช้ได้ทั้งสองแบบ
การเรียก method จากข้อมูลโดยตรงใน  Yuescript ไม่ต้องใส่วงเล็บครอบตัวข้อมูลเหมือนใน Lua

a = {}
for w in string.gmatch "Hello world!", "[^%s]+" do a[#a+1] = w

b = for w in "Hello world!"\gmatch "%S+" do w -- ใช้ for เป็น expression

c = [w for w in "Hello world"::gmatch "%w+"] -- ใช้ list comprehension

อ่านไฟล์

Python

อ่านทั้งไฟล์


f = open("my-file.txt")
file_content = f.read()
f.close()

# หรือ
with open("my-file.txt", "r") as f:
    file_content = f.read()

อ่านทีละบรรทัด


f = open("my-file.txt")
for line in f.readlines():
    print(line)
f.close()

# หรือ
with open("my-file") as f:
    for line in f.readlines():
        print(line)

Lua

อ่านทั้งไฟล์


local f = io.open("my-file.txt", "r")
local file_content = f:read "a" -- mode "a" คืออ่านทั้งไฟล์
f:close()

-- หรือ
f = io.input "my-file.txt" -- ให้รับ input จากไฟล์
file_content = io.read("a")
io.input(io.stdin) -- เปลี่ยนกลับมารับ input จาก standard input (keyboard)
io.close(f) -- เหมือน f:close()

อ่านทีละบรรทัด


f = io.open "my-file.txt" -- ไม่กำหนด mode จะเป็นการเปิดไฟล์เพื่ออ่าน
local line = f:read() -- ไม่กำหนด mode คืออ่านทีละบรรทัด
while line do
  print(line)
  line = f:read()
end
io.close(f) -- เหมือน f:close()

--หรือ
f = io.open "my-file.txt"
for line in f:lines() do print(line) end
f:close()

--หรือ
for line in io.lines "my-file.txt" do
  print(line)
end -- จบลูป (อ่านจนหมดไฟล์) แล้วจะปิดไฟล์ให้เอง

Fennel

with-open จะปิดไฟล์ให้อัตโนมัติเมื่อจบแล้ว return ค่า expression สุดท้ายใน form

อ่านทั้งไฟล์


(var file-content (let [f  (io.open "my-file.txt")
                        fc (f:read :a)]
                    (f:close)
                    fc))

;; หรือ
(set file-content (with-open [f (io.open "my-file.txt" :r)]
                    (f:read :a))

;; หรือ
(set file-content (match (io.open "test2.txt")
                    f (f:read "a")))

อ่านทีละบรรทัด


(with-open [f (io.open :my-file.txt)]
  (each [line (f:lines)]
    (print line)))

;; หรือ
(each [line (io.lines "my-file.txt")]
  (print line))

Yuescript

อ่านทั้งไฟล์


with io.open "my-file.txt"
  file_content = ::read "a"
  \close!

-- หรือ
f = io.open "my-file.txt"
file_content = f\read "a"
f::close! -- หรือ f\close! หรือ io.close f

อ่านทีละบรรทัด


with io.open "my-file.txt"
  for line in \lines!
    print line
  ::close!

-- หรือ
for line in io.lines "test2.txt"
  print line

เงื่อนไข

Python

เงื่อนไขเดียว


a = ""
if 1 < 2:
    a="no"
else:
    a="yes" 

b = "yes" if 1 < 2 else "no"

c = ("no", "yes")[1 < 2] # Python True เท่ากับ 1 และ False เท่ากับ 0

d = {True: "yes", False: "no"}[1 < 2]

หลายเงื่อนไข


result = None
if 1 < 2:
    result = "1 < 2"
elif 1 > 2:
    result = "1 > 2"
else:
    result = "1 = 2"

Lua

เงื่อนไขเดียว


local a
if 1 < 2 then a = "yes" else a = "no" end

local b = 1 < 2 and "yes" or "no" -- แบบ short circuit ระหว่าง and กับ or ต้องไม่เป็นค่า false

local c = ({[true]="yes", [false]="no"})[1 < 2]

หลายเงื่อนไข


local result1
if 1 < 2 then
  result1 = "1 < 2"
elseif 1 > 2 then
  result1 = "1 > 2"
else
  result1 = "1 = 2"
end

local result2 = 1 < 2 and "1 < 2" or 1 > 2 and "1 > 2" or "1 = 2"

Fennel

if ใน Fennel เป็น expression

เงื่อนไขเดียว


(var a (if (< 1 2) "yes" "no"))

(var b (if (< 1 2)
         (do     ; กรณีทำหลาย expression ในเงื่อนไขเดียวใช้ do ช่วย
           (print "1 < 2")
           "yes")
         "no"))

(var c (match (< 1 2)
         true "yes"
         _    "no"))

;; หรือถ้าไม่มี else จะใช้ when แทนก็ได้ไม่ต้องใส่ do ครอบหลาย expression
(when (< 1 2)
  (print "1 < 2")
  (print "yes"))

หลายเงื่อนไข


(var result (if (< 1 2) "1 < 2"
                (> 1 2) "1 > 2"
                "1 = 2"))

Yuescript

if ใน Yuescript เป็น expression

เงื่อนไขเดียว


a = ""
if 1 < 2 then a = "yes" else a = "no" -- if บรรทัดเดียวต้องมี then เหมือน lua แต่ไม่ต้องมี end

b = if 1 < 2 then "yes" else "no" -- if เป็น expression ได้

หลายเงื่อนไข


result1 = ""
if 1 < 2
  result1 = "1 < 2"
elseif 1 > 2
  result1 = "1 > 2"
else
  result1 = "1 = 2"

result2 = if 1 < 2
  "1 < 2"
elseif
  "1 > 2"
else
  "1 = 2"

result3 = if 1<2 then "1 < " elseif 1>2 then "1 > 2" else "1 = 2"

result4 = switch true
  when 1<2
    "1 < 2"
  when 1>2
    "1 > 2"
  else
    "1 = 2"

การวนซ้ำ

Python

การวนซ้ำและพิมพ์ค่าสมาชิกใน list


list1 = [1, 2, 3, 4]
for x in list: print(x)

การประมวลผลฟังก์ชันกับแต่ละสมาชิกใน list


def add10(x):
    return x + 10

list2 = []
for x in list1: list2.append(add10(x))

# หรือ
list2 = [add10(x) for x in list1]

Lua

การวนซ้ำและพิมพ์ค่าสมาชิกใน table


local list1 = {1, 2, 3, 4}
for _, v in ipairs(list1) do print(v) end

การประมวลผลฟังก์ชันกับแต่ละสมาชิกใน table


function add10(x) return x+10 end -- หรือ add10 = function(x) return x+10 end

local list2 = {}
for _, v in ipairs(list1) do table.insert(list2, add10(v)) end

Fennel

การวนซ้ำและพิมพ์ค่าสมาชิกใน list


(local list1 [1 2 3 4])
(each [_ v (ipairs list1)] (print v))

การประมวลผลฟังก์ชันกับแต่ละสมาชิกใน list


(var add10 #(+ $1 10)) ; หรือ (fn add10 [x] (+ x 10))

(var list2 (let [lst []]
             (each [_ v (ipairs list1)] (table.insert lst (add10 v)))
             lst))
;; หรือ
(var list2 (icollect [_ v (ipairs list1)] (add10 v)))

Yuescript

สามารถใช้ ipairs() เหมือนใน Lua และยังสามารถใช้ * เพื่อดึงเฉพาะสมาชิกใน list เหมือน Python

การวนซ้ำและพิมพ์ค่าสมาชิกใน list


list1 = {1, 2, 3, 4}
for _, v in ipairs list1 do print v -- for บรรทัดเดียวต้องมี do เหมือน Lua แต่ไม่ต้องมี end

-- หรือ
for v in *list1 do print v -- ใน for ลูปสามารถใช้ *list1[2,3] เพื่อ slice เฉพาะสมาชิกตัวที่ 2 ถึง 3 ของ list1 ได้

การประมวลผลฟังก์ชันกับแต่ละสมาชิกใน list


add10 = (x) -> x+10

list2 = for v in *list1 do add10 v -- ถ้าใช้ for เป็น expression จะคืนค่าเป็น list ของแต่ะ expression สุดท้ายใน loop

-- หรือ
list3 = [add10 v for _, v in ipairs list1] -- แบบ list comprehension คล้ายกับ Python แต่ใช้ when แทน if

แรงบัลดาลใจและอ้างอิงจาก CHICKEN for Python programmers

ความคิดเห็น