2008年4月29日

整合Unicode核心和圖形介面的版本

REBOL 3今天釋出內部版本2.100.8,將圖形次系統加入Unicode核心中。體積從221 KB變成523 KB。目前這個版本尚欠缺一些常用的網路通訊協定,欠缺一些編碼解碼器,圖形介面的部分也尚未支援Unicode文字的展示。詳細的說明,請見http://www.rebol.net/wiki/R3_Releases

2008年4月26日

關於meta-programming

我在這篇文章中提到,對於DSL的支援良窳,我的三個基本的判斷原則是: (1) 能否輕易地設計DSL (2) 能否設計出有彈性的DSL (3) 能否讓DSL和GPL使用上合為一體。我覺得REBOL這三方面都做得相當好,是最棒的meta-programming語言。用REBOL設計出來的DSL,稱為Dialect。

2008年4月20日

Web顏色名稱

REBOL沒有支援標準的Web顏色名稱(共140個)。如果你想使用這些標準顏色名稱,你可以使用下面的定義。從這個顏色名稱的定義中,可以看出文化差異。譬如鮭魚、石板、綠松石、北美印第安人穿的鹿皮軟鞋都可當作顏色名稱,和我們東方社會的習慣差異很大。

詳細的顏色,請參考這個網頁
do web-colors: [ {愛麗絲藍} AliceBlue: 240.248.255 {古董白} AntiqueWhite: 250.235.215 {水} Aqua: 0.255.255 {海藍寶石} Aquamarine: 127.255.212 {蔚藍} Azure: 240.255.255 {米色} Beige: 245.245.220 {陶器} Bisque: 255.228.196 {黑} Black: 0.0.0 {白杏仁} BlanchedAlmond: 255.235.205 {藍} Blue: 0.0.255 {藍紫} BlueViolet: 138.43.226 {褐} Brown: 165.42.42 {木材} BurlyWood: 222.184.135 {軍官藍} CadetBlue: 95.158.160 {淡黃綠} Chartreuse: 127.255.0 {巧克力} Chocolate: 210.105.30 {珊瑚} Coral: 255.127.80 {矢車菊藍} CornflowerBlue: 100.149.237 {玉米穗絲} Cornsilk: 255.248.220 {緋紅} Crimson: 220.20.60 {青綠色} Cyan: 0.255.255 {暗藍} DarkBlue: 0.0.139 {暗青} DarkCyan: 0.139.139 {暗金黃桿} DarkGoldenRod: 184.134.11 {暗灰} DarkGray: 169.169.169 {暗灰} DarkGrey: 169.169.169 {暗綠} DarkGreen: 0.100.0 {暗卡其} DarkKhaki: 189.183.107 {暗洋紅} DarkMagenta: 139.0.139 {暗橄欖綠} DarkOliveGreen: 85.107.47 {暗橙} DarkOrange: 255.140.0 {暗蘭花} DarkOrchid: 153.50.204 {暗紅} DarkRed: 139.0.0 {暗鮭魚} DarkSalmon: 233.150.122 {暗海綠} DarkSeaGreen: 143.188.143 {暗石板藍} DarkSlateBlue: 72.61.139 {暗石板灰} DarkSlateGray: 47.79.79 {暗石板灰} DarkSlateGrey: 47.79.79 {綠松石} DarkTurquoise: 0.206.209 {暗紫色} DarkViolet: 148.0.211 DeepPink: 255.20.147 DeepSkyBlue: 0.191.255 DimGray: 105.105.105 DimGrey: 105.105.105 DodgerBlue: 30.144.255 FireBrick: 178.34.34 FloralWhite: 255.250.240 ForestGreen: 34.139.34 Fuchsia: 255.0.255 Gainsboro: 220.220.220 GhostWhite: 248.248.255 Gold: 255.215.0 GoldenRod: 218.165.32 Gray: 128.128.128 Grey: 128.128.128 Green: 0.128.0 GreenYellow: 173.255.47 HoneyDew: 240.255.240 HotPink: 255.105.180 IndianRed: 205.92.92 Indigo: 75.0.130 Ivory: 255.255.240 Khaki: 240.230.140 Lavender: 230.230.250 LavenderBlush: 255.240.245 LawnGreen: 124.252.0 LemonChiffon: 255.250.205 LightBlue: 173.216.230 LightCoral: 240.128.128 LightCyan: 224.255.255 LightGoldenRodYellow: 250.250.210 LightGray: 211.211.211 LightGrey: 211.211.211 LightGreen: 144.238.144 LightPink: 255.182.193 LightSalmon: 255.160.122 LightSeaGreen: 32.178.170 LightSkyBlue: 135.206.250 LightSlateGray: 119.136.153 LightSlateGrey: 119.136.153 LightSteelBlue: 176.196.222 LightYellow: 255.255.224 Lime: 0.255.0 LimeGreen: 50.205.50 Linen: 250.240.230 Magenta: 255.0.255 Maroon: 128.0.0 MediumAquaMarine: 102.205.170 MediumBlue: 0.0.205 MediumOrchid: 186.85.211 MediumPurple: 147.112.216 MediumSeaGreen: 60.179.113 MediumSlateBlue: 123.104.238 MediumSpringGreen: 0.250.154 MediumTurquoise: 72.209.204 MediumVioletRed: 199.21.133 MidnightBlue: 25.25.112 MintCream: 245.255.250 MistyRose: 255.228.225 Moccasin: 255.228.181 NavajoWhite: 255.222.173 Navy: 0.0.128 OldLace: 253.245.230 Olive: 128.128.0 OliveDrab: 107.142.35 Orange: 255.165.0 OrangeRed: 255.69.0 Orchid: 218.112.214 PaleGoldenRod: 238.232.170 PaleGreen: 152.251.152 PaleTurquoise: 175.238.238 PaleVioletRed: 216.112.147 PapayaWhip: 255.239.213 PeachPuff: 255.218.185 Peru: 205.133.63 Pink: 255.192.203 Plum: 221.160.221 PowderBlue: 176.224.230 Purple: 128.0.128 Red: 255.0.0 RosyBrown: 188.143.143 RoyalBlue: 65.105.225 SaddleBrown: 139.69.19 Salmon: 250.128.114 SandyBrown: 244.164.96 SeaGreen: 46.139.87 SeaShell: 255.245.238 Sienna: 160.82.45 Silver: 192.192.192 SkyBlue: 135.206.235 SlateBlue: 106.90.205 SlateGray: 112.128.144 SlateGrey: 112.128.144 Snow: 255.250.250 SpringGreen: 0.255.127 SteelBlue: 70.130.180 Tan: 210.180.140 Teal: 0.128.128 Thistle: 216.191.216 Tomato: 255.99.71 Turquoise: 64.224.208 Violet: 238.130.238 Wheat: 245.222.179 White: 255.255.255 WhiteSmoke: 245.245.245 Yellow: 255.255.0 YellowGreen: 154.205.50]

2008年4月18日

DevCon 2008

據說原本預估9月要在布拉格舉辦的DevCon已經取消。要等到REBOL 3.0完成之後,才會舉辦。

2008年4月17日

About the Erlang VS. REBOL Series

I know this series is a mess. I promise to write an organized version in English when I have time. It's a rain check.

2008年4月16日

Erlang VS. REBOL, Part VI

* if 與 case
Erlang的if 相當於REBOL的case;Erlang的case相當於REBOL的switch。Erlang的if與case都可以搭配guard使用,但REBOL沒有guard的觀念。

* 將資料放入List
在Erlang中,將資料插入List頭部,是最有效率的作法。但REBOL則是插入尾部才有效率。

* Exception
在Erlang程式中主動發出例外,有三種方式
exit(Why)
throw(Why) 類似Java的可處理例外
erlang:error(Why) 類似Java的Error(嚴重的狀況)

REBOL的例外只有一種,類似上面第二種。

* try/catch
Erlang的try/catch語法比REBOL豐富,類似Java的try/catch/finally。
try FuncOrExpressionSequence of
Pattern1 [when Guard1] -> Expressions1;
Pattern2 [when Guard2] -> Expressions2;
...
catch
ExceptionType: ExPattern1 [when ExGuard1] -> ExExpressions1;
ExceptionType: ExPattern2 [when ExGuard2] -> ExExpressions2;
...
after
AfterExpressions
end


* Stack Trace
erlang:get_stack_trace()可以取得目前的堆疊。REBOL具有類似功能的stack函數。

* Binary
Erlang的binary寫法類似List,但[…]改用<< >>,且每個值都必須介於0到255之間,例如:
<<5,10,20>>

* Bit Syntax
Erlang具有位元語法,可以方便二元檔案或網路封包處理。例如:

> Red = 2
> Green = 61
> Blue = 20
> Mem = << Red:5,Green:6,Blue:5 >>
<<23,180>>

Bit Syntax甚至可以讓你指定big-endian或little-endian或native-endian、signed或unsigned、integer或float或binary。

* 使用者自訂的模組屬性
REBOL和Erlang都允許使用者自行定義的模組屬性。
Erlang:
-my-info(taiwan).

REBOL:
REBOL[

My-info: 'Taiwan
]


* Apply
REBOL和Erlang都支援apply函數。

* Preprocessor
Erlang具有前處理器,用來將檔案含括(include)進來。例如:
-include(FileName)

* Macro
Erlang具有Macro,例如:

-define(macro1(X, Y), {a, X, Y}).
foo(A) ->
?macro1(A+10, b)


會變成

foo(A) ->
{a,A+10,b}.



Erlang VS. REBOL, Part V

* List Comprehension
Erlang支援List Comprehension;REBOL雖然沒有List Comprehension,但是要設計一個方言來達到List Comprehension,應該不難。

Erlang:

> L = [1,2,3,4,5]
> [2*X || X <- L]
[2,4,6,8,10]

下面是另一個例子,利用List Comprehension寫出簡短的Quick Sort:
lib_misc.erl
lib_misc.erl
qsort([]) -> [];
qsort([Pivot|T]) ->
qsort([X || X <- T, X < Pivot])
++ [Pivot] ++
qsort([X || X <- T, X >= Pivot]).

1> L=[23,6,2,9,27,400,78,45,61,82,14].
[23,6,2,9,27,400,78,45,61,82,14]
2> lib_misc:qsort(L).
[2,6,9,14,23,27,45,61,78,82,400]


再來一個例子:

lib_misc.erl
perms([]) -> [[]];
perms(L) -> [[H|T] || H <- L, T <- perms(L--[H])].
> lib_misc:perms("123").
["123","132","213","231","312","321"]
> lib_misc:perms("cats").
["cats", "cast", "ctas", "ctsa", "csat", "csta", "acts", "acst", "atcs", "atsc", "asct", "astc", "tcas", "tcsa", "tacs", "tasc", "tsca", "tsac", "scat", "scta", "sact", "satc", "stca", "stac"]


List Comprehension的語法之簡潔,威力之強大,實在有一點恐怖。

* 等於
Erlang的等於符號是「=:=」與「==」;REBOL的等於符號是「=」與「==」。

* Bitwise運算子
Erlang具有下列的Bitwise運算子bnot、band、bor、bxor、bsl、bsr;REBOL不具有bitwise運算子,但有某些型別和函數具有類似功能,例如logic!型別、shift函數。

* Short-Circuit運算子
Erlang具有orelse和andalso這兩個short-circuit運算子。REBOL的AND和OR則「不是」Short-Circuit,但ANY和ALL可以達到Short-Circuit的效果。

* Guard
Erlang某些地方可以用到Guard,以補模式比對的不足。Guard的運算結果為true或false。

REBOL沒有模式比對的概念,所以沒有Guard。

*Record
Erlang利用Record來模擬物件,Record其實就是Tuple,只是每個元素都有對應的名稱。REBOL的Object和Erlang的Record很類似。

定義record時利用「-record」命令。存放Record定義的檔案,副檔名為.hrl。下面是一個範例:
Records.hrl
-record(todo, {status=reminder,who=jerry,text}).

上面的檔案定義了一個todo記錄結構,使用rr函數(read record)可以將它載入:
> rr("records.hrl").

建立的方式:
> X=#todo{}.
#todo{status = reminder,who = joe,text = undefined}
> X1 = #todo{status=urgent, text="Fix errata in book"}.
#todo{status = urgent,who = joe,text = "Fix errata in book"}
> X2 = X1#todo{status=done}.
#todo{status = done,who = joe,text = "Fix errata in book"}
> X2#todo.text.
"Fix errata in book"

Erlang VS. REBOL, Part IV

* 匯出全部

Erlang允許個模組將自己的函數全部匯出:
-compile(export_all)

REBOL雖然沒有這樣的作法。但是REBOL模組中沒有被匯出者,依然可以透過explicit的方式,被外部使用,例如:
my-module/non-expoted-func

* Arity
對Erlang來說,Arity(引數的個數)是函數的一部份,函數area/1表示函數名為area,且具有一個引數。而area/1可能又有許多個clause。同一個Erlang模組內,即使函數名稱一樣,但Arity不同,那麼就是完全不同的函數。Erlang常常會使用相同名稱但不同Arity的函數,當作輔助函數(helper)。

REBOL函數不具有clause,也不強調Arity。

* 匿名函數
Erlang和REBOL都支援匿名函數。

Erlang:
fun(x) -> x * 2 end.

REBOL:
func[x] [x * 2]

但是Erlang的匿名函數可以有多個clause,REBOL則不行。

* 較高次方函數
Erlang和REBOL也都支援「較高次方」函數(higher-order function),也就是「以函數為引數或傳出值」的函數。較高次方函數是Function Programming很重要的特色。

Erlang大量使用「較高次方」函數,但REBOL卻很少使用「較高次方」函數。

* 把函數當引數用
Erlang有相當多list-at-a-time函數,可以將對整個list的操作,當作單一個概念。簡化我們的思考,也簡化我們的程式。REBOL也可以做到這一點,設計出block-at-a-time函數,只是目前好像這樣的函數並不多(但MAP是個例外)。而且許多時候,REBOL都是利用block來當作函數(不像函數那麼有彈性)。這一點,我比較喜歡Erlang。

Erlang:
> Double = fun(x) -> x * 2 end.
> L = [1,2,3,4]
> list:map(Double, L).
[2,4,6,8]

* 把函數當傳出值用
Erlang可以將函數當傳出值,例如:
> Fruit = [apple,pear,orange].
> MakeTest = fun(L) -> (fun(X) -> lists:member(X, L) end) end.
> IsFruit = MakeTest(Fruit).
> IsFruit(apple).
true
> IsFruit(beef).
false

REBOL必須透過closure,才能做到這件事:
>> Fruit: [apple pear orange]
>> Make-Test: closure [L] [ func[X] [found? Find L X] ]
>> Is-Fruit: Make-Test Fruit
>> Is-Fruit 'apple
== true
>> Is-Fruit 'beef
== false

不管是Erlang或REBOL,「把函數當傳出值用」都很少見。但是利用這種方式建立自己的流程控制,可以相當有效地減少程式體積,有時候甚至會讓程式更清晰易讀。

Erlang VS. REBOL, Part III

* String
Erlang String其實就是List,所以下面三者雖然寫法不同,但意義完全相同。
[65, 66, 67]
[$A, $B, $C]
"ABC"

Erlang的字串使用Latin-1(ISO-8859-1),能表示的字元相當有限。REBOL的字串使用Unicode,可以表示任何國家的文字。

* Un-bind
Erlang有一個函數f(),可以用來將所有的binding解除。REBOL不具有這樣的函數。

Erlang:
> X = 10.
10
> X.
10
> f().
> X.
* 1: veriable 'X' is unbound

*副檔名(file extension)
Erlang源碼使用的副檔名為.erl;REBOL則是.r。Erlang編譯後的模組檔名為.beam;REBOL不需要編譯。你可以使用c()函數來編譯Erlang模組。

*模組定義
Erlang和REBOL都可以定義模組。

Erlang在源碼檔案前這麼寫:
-module(geometry).
-export([area/1]).
-vsn(1234).

REBOL在源碼檔案前這麼寫:


REBOL [
Name: geometry
Version: 1.0.0
Type: module
Export: [area-rect area-circle]
]
對Erlang來說,沒有被匯出者,無法在別的地方使用。但是對REBOL來說,即時沒有被匯出,依然可以在其他地方被使用,只要註明模組為何即可,例如:
my-module/non-exported-word

* 函數與Clause
Erlang的函數可以包含許多Clause。Clause之間用英文分號隔開,最後一個Clause用英文句號結束。例如:

area({rectangle, Width, Ht}) -> Width * Ht;
area({circle, R}) -> 3.14159 * R * R.

呼叫函數的時候會先進行模式比對(Pattern Matching),找出適合的Clause呼叫。

REBOL不具有Clause的概念。上面的程式要改寫成:
Area-Rect: func [ Width Ht ] [ Width * Ht ]
Area-Circle: func [ R ] [ 3.14159 * R * R ]

* 編譯與呼叫模組
Erlang程式要編譯成模組才能執行,你可以使用c()函數來編譯Erlang模組。呼叫某Erlang模組的某函數時,使用英文冒號當作模組和函數之間的分隔符號。

Erlang:
1> c(geometry).
{ok,geometry}
2> geometry:area({rectangle, 10, 5}).
50
3> geometry:area({circle, 1.4}).
6.15752

你也可以利用下面的方式,將模組匯入(import),就可不用在呼叫函數時前面冠上模組名稱和冒號:
-import(geometry, [area/1])
area({rectangle, 10, 5})


REBOL不需要編譯。可以利用import將模組匯入。呼叫函數時,可以用implicit的方式(不註明模組),也可以用explicit的方式(註明模組,用斜線當分隔符號)

mod: import ' geometry
area-rect 10 20
mod/area-rect 10 20

Erlang VS. REBOL, Part II

* Word與Atom
Erlang所謂的Atom,其實就是REBOL所謂的Word。Erlang規定Atom只能使用小寫字母、底線(_)、阿拉伯數字。REBOL對於Word沒有這樣的規範,REBOL的Word甚至可以使用各國文字(因為REBOL有支援Unicode)。Erlang的Atom沒有繫結值(也可以視為繫結到自己),而變數有繫結值;REBOL則不管有沒有繫結值,一律都是Word。

* Erlang Tuple – REBOL Block
Erlang所謂的Tuple,其實就是REBOL的Block。Erlang Tuple使用{},且元素之間要用逗號(,)隔開;REBOL使用[]。

Erlang:
{"Jerry", "Tsai", 1.77 }

REBOL:
["Jerry" "Tsai" 1.77 ]

* Object
許多Erlang使用Tuple的場合,在REBOL中不見得要用Block,可以改用Object,但Erlang不支援Object。

* Unification
使用模式比對(Pattern Matching)來取出值,稱為Unification。Erlang有支援Unification。REBOL則必須透過Set函數。

Erlang:
P = {"Jerry", "Tsai", 1.77 }
{F, L, H} = P
現在F被繫結到"Jerry";L被繫結到"Tsai";H被繫結到1.77。

REBOL的寫法:
P: ["Jerry" "Tsai" 1.77 ]
Set [F L H] P

* Erlang List – REBOL Block
除了Tuple,Erlang還有List(清單)。你可以把Tuple(值組)想成是C語言的Struct,List想成是動態陣列。Erlang所謂的Tuple和List,對REBOL來說都是Block。

Erlang:
T = [1, 2, 3]
L = [4, 5|T]

相當於REBOL:
T: [1 2 3]
L: Join [ 4 5 ] T

* 取出List元素
Erlang List的Head可以非常有效率地被取出。幾乎所有處理List的函數,都是先取出Head,做處理,再遞迴地處理Tail。

Erlang:
[X|Y] = L

或者利用BIF(Build-in Function)
X = hd(L)
Y = tl(L)

REBOL的作法:
X: First L
Y: Next L

Erlang VS. REBOL, Part I

* 語言種類
Erlang屬於Pure Functional Language。REBOL屬於Impure Functional Language。Erlang的許多設計考量,是為了方便進行concurrency。REBOL的設計則最適合進行Meta-Programming。

* 註解(Comment)
Erlang使用「%」,REBOL使用「;」,當作單行註解記號。

* 算術表示式 2 + 3 * 4
Erlang: 2 + 3 * 4 (寫法比較直覺)
REBOL: 2 + (3 * 4) (一定要寫括號,不然一律由左至右計算)

* Integer Overflow?
Erlang使用任意長度的整數,來進行算術運算,不會發生overflow。
REBOL使用64位元長度記錄整數,有可能發生overflow。

Erlang:
> 12345678 * 987654321 * 112233445566778899 * 998877665544332211.
(A very huge number. No problem here)

REBOL:
>> 12345678 * 987654321 * 112233445566778899 * 998877665544332211
** Math error: Math or number overflow

* 不同基底的整數
Erlang可以使用任何基底,例如:
16#cafebabe (表示16進位)
17#cafebabe (表示17進位)

REBOL做不到這一點。

* 變數名稱
Erlang的變數必須頭文字大寫,且只能使用英文和數字。REBOL不區分大小寫,可以使用各國文字。

* 變數範疇
Erlang的變數範疇(scope)只有在clause內。不同的clause之間不可能共享變數。REBOL沒有此限制。

* 變數繫結
Erlang的變數只能被繫結(bound)一次(可以讓除錯變得很容易)。REBOL沒有此限制。

2008年4月13日

Keep IT Simple 歌詞

我喜歡的歌手之一Van Morrison,最近(四月)推出的專輯,就名為「Keep it Simple」,你可到Van Morrison的官方網站聽這首歌的Audio Clip。

「Keep IT Simple」碰巧也是REBOL的Slogan,只不過這裡的IT要大寫,表示「Information Technologies」(資訊科技)的意思。IT往往搞得過度複雜,而REBOL正致力於破除這一點。

我把這首歌的歌詞改編如下,希望能在下次REBOL DevCon時登台演唱這首歌(I am just kidding):

Keep IT Simple

原創:Van Morrison
改編:Jerry Tsai

They mocked me when I was singing the songs
Trying to go forward to something more simple than we have
They mocked me ‘cos I told it like it was

Wrote about slowness and monolith
Wrote about what we really didn’t need in our code
Make us work like a horse

Dream software systems on the one hand
And straight reality is always cold
Blame it on the programming language
It’s not your fault at all

Mocked me when it got out of hand
Nobody tried to understand
Now we got to keep it simple and that’s that

Dream software systems on the one hand
And straight reality is always cold
Blame it on the programming language
It’s not your fault at all

Can’t find the bugs while I am writing code
It happens many times before
Hay, we got to keep it simple to save ourselves

Mocked me when I tried to go forward
Said the train was completely off the track
And we got to go forward to something simple to save ourselves

Whoa we got to leave .NET for REBOL just to save yourselves
Well got to leave Java for REBOL just to save yourselves
Well you got to keep it simple, keep it simple just to - and that’s that

Whoa you got to keep it simple nowadays and that’s just that
Whoa you got to keep it simple nowadays and that’s just the way it is
And you got to keep it simple these days ‘cos that’s the way it is

Well you got to keep it, keep it simple and that’s that

REBOL投影片


我開始利用閒暇時間,製作「認識REBOL」投影片。我喜歡用圖解說,不喜歡用Bullet Point,所以這份投影片會繪製許多示意圖。 此Blog的許多圖,就是來自這份教材。
我希望這份教材至少能完整地涵蓋REBOL User's Guide,加上VID、CGI、聲音。其他的部分會不會加進來,就不一定了。

GUI架構


REBOL的GUI是以GOB為核心,GOB的設計考慮到效率和彈性。GOB的下層目前是AGG的2D繪圖引擎,以後還有可能加上OpenGL/DirectX等3D引擎。

你可以只利用GOB和View設計出REBOL的GUI程式(我的舊版本Transma程式,就只有使用到GOB和View,沒用到VID),但是這麼做的複雜度比較高,大多數的人會使用VID。VID是一種高階的視覺化介面方言,將下面的細節隱匿起來。VID也具有Skin(轉換不同視覺外觀)的能力。

2008年4月12日

CJK地區,誰在注意REBOL?


你可以到這個網址,看到世界各地的都市中,有哪些人在造訪REBOL.com。在CJK(中日韓)地區,以北京、台北、澳門的造訪者最多。詳細的中國地圖,請見這裡
註:Macao也可以寫成Macau。

用Draw方言繪製發光文字


REBOL Draw底層使用AGG 2.4當繪圖引擎,繪圖能力很強。這裡是一個範例展示:

REBOL[]

my-font: make system/standard/font [
name: "Times New Roman" size: 64
]

draw-block: [ ]

for i 0 9 1 [
j: to-integer (255 / 10.0 * (i + 1))
append draw-block compose/deep [
pen (to-tuple reduce [ j j 255 ] )
line-width (10 - i)
line-join round
fill-pen none
text 10x0 vectorial [
font my-font bold "REBOL"
]
]
]

append draw-block compose [
fill-pen black
text 10x0 vectorial [
font my-font bold "REBOL"
]
Fill-pen Red
text 142x0 vectorial [
font my-font bold "O"
]
]

win: make gob! [
size: 360x130
color: black
]

append win g: make gob! compose [
size: ( win/size )
offset: 0x0
]

g/draw: draw-block

view win

2008年4月9日

REBOL的註解

REBOL的註解,是從英文分號「;」開始,到該行結束為止。例如:

name: "John Doe" ; 預定使用者名稱

你也可以使用comment函數,此函數後面需要一個參數,此參數會被視為註解,不予執行。例如:

comment 100

利用{}字串或 []區塊當參數,comment可以延續許多行,例如:

comment [
多行的註解
]

comment {
多行的註解
}

我們盡量使用{}字串當comment參數,而不要用[]區塊當其參數,因為[]區塊內還是要遵守REBOL型別的規範,不能隨意寫。例如:

comment [
OK :)
]
**Syntax Error

而{}字串就沒有這樣的問題。

comment {
OK :)
}

其實,許多出現comment { … }的地方,都可以將comment省略,直接寫{ … },例如:

pi: 3.14 {圓周率}

這類多餘的值,會被REBOL解譯器丟棄,不會有作用,所以可以當成註解使用。

2008年4月6日

關於Block的操作

【什麼是Block】
利用block,可以將多個值聚在一起。如下所示:

[ 1 "one" "uno" "一" ]

一個block內的值,型別可以不一致。以上面的例子來說,1是integer!,而另外三個是string!。

下面的block,是Jerry的個人資料:

user-info: [ "Jerry" "Tsai" JerryTsai@gm.com ]

你可以利用下面的方式,取得Jerry的電子郵件:

user-info/3

其實上面的寫法和下面的意義完全一樣:

pick user-info 3

除了pick之外,這篇文章與這篇文章所提到的函數,也都可以用來處理block。

【使用標籤】
上面的block組織方式有一個缺點,例如,某天你可能會想要在last-name與email之間新增「語言」欄位,變成:

user-info: [ "Jerry" "Tsai" "Chinese" JerryTsai@gm.com ]

如此一來,你就必須把「user-info/3」改成「user-info/4」,否則取得的不是電子郵件,而是語言。如果有這樣的顧慮,可以在每個資料前面加上一個word,當作標籤:

user-info: [ last-name "Jerry" first-name "Tsai" language "Chinese" email JerryTsai@gm.com ]

這麼一來,就可以用下面的方式來取得電子郵件資料:

user-info/email

上面的寫法和下面的作用一樣:

select user-info 'email

對於select來說,任何值都可以當作「標籤」,不一定要是word!。select單純就是在陣列中找出相同的元素,然後傳出「下一個元素」。如下面所示:

>> select [ 1 "one" 2 "two" 3 "three" ] 2
== "two"

由於select處理block資料時,是從頭開始一個一個比對,所以當block內的元素個數很多時,select的效率可能會很差。這個時候不要再使用block!,要改用map!(我以後會寫文章介紹。)

【套疊的block】

如果我的電子郵件帳號不只一個,可以寫成下面這樣:
user-info: [ "Jerry" "Tsai" [JerryTsai@gm.com jtsai@hmail.com]]

這個時候,使用user-info/3就會取得[JerryTsai@gm.com jtsai@hmail.com]。像這種block內還有block的套疊(nested)組織方式,在REBOL程式中很常見。

你可能會想利用套疊的方式,做出簡單的資料庫。下面的例子中,Users裡面有三筆紀錄:

; 方法1
users: [
[ first-name "Jerry" last-name "Tsai" email JerryTsai@gm.com ]
[ first-name "Terry" last-name "Gao" email tgao@gmail.com ]
[ first-name "Mary" last-name "Lee" email m.lee@gmail.com ]
]

當資料量一大,裡面重複出現first-name、last-name、email這些word,很浪費儲存空間。這個時候還是將它們省略比較好:

; 方法2
users: [
[ "Jerry" "Tsai" JerryTsai@gm.com ]
[ "Terry" "Gao" tgao@gmail.com ]
[ "Mary" "Lee" m.lee@gmail.com ]
]

【攤平套疊的block】
當每筆記錄的元素個數相同,且欄位意義都一樣時,我們可以將它們攤平,變成這樣:

; 方法3
users: [
"Jerry" "Tsai" JerryTsai@gm.com
"Terry" "Gao" tgao@gmail.com
"Mary" "Lee" m.lee@gmail.com
]

這麼做有一個很大的優點。REBOL有許多block相關的函數都有提供/skip修飾字,可以將固定數目的元素視為一筆記錄,進行處理。至於方法2,則無法做這樣的處理。如果想將每三個元素當成一筆記錄,以每筆記錄的第一個欄位(first-name)做比較,進行排序,作法是這樣:

sort/skip users 3

如果想比較的欄位不是第一個,而是第二個(last-name),則使用/compare,作法是這樣:

sort/skip/compare users 3 2

不幸的是,有一些函數應該要具有/compare修飾字,但事實卻不然(例如FIND)。還有一些函數應該要具有/compare修飾字,但事實卻不然,甚至連/skip都沒有支援(例如maximum-of)。我已經將這些函數整理出來,向REBOL公司提出要求,接下來就看他們是否要支援了。

你可以利用extract函數,固定每隔幾個位置,就取出元素,做出一個block:

>> first-names: extract users 3
== ["Jerry" "Terry" "Mary"]

請注意,extract並不會破壞原始的block,所以在執行完上面之後,users的內容還是一樣。

利用extract的/index修飾字,可以在一開始產生一個位移,取出別的欄位。例如,下面分別取出全部的last-name和全部的電子郵件:

last-names: extract/index users 3 2
emails: extract/index users 3 3

(介紹我向REBOL公司提議的interleave函數)

在Block內安插換行記號

如果你想在console將block列印出來,你可能會希望block的內容不要擠在一起。其實,你可以在block內插入一些換行的記號,你可以每個元素後面插入換行記號,或者每隔n個元素後面插入換行記號。請看下面的範例:

>> data: [ 1 "A" 2 "B" 3 "C" ]
== [ 1 "A" 2 "B" 3 "C" ]
>> new-line/skip data true 2

new-line是一個函數(不要和newline混淆了,newline是一個字元)。上面的指令意思是:在data內每隔2個元素插入一個換行記號。true表示「要加入換行記號」。執行完後,你會發現現在每兩個元素就會換行:

>> data
== [
1 "A"
2 "B"
3 "C"
]

你可以利用new-line?來判斷某block是否具有換行記號:

>> new-line? data
== true

你可以利用new-line將換行記號移除:

>> new-line/all data false
== [ 1 "A" 2 "B" 3 "C" ]

Series函數總整理

本來想要將所有和Series相關的函數全都繪製成圖,但是過去三篇貼文所呈現的效果並不好,所以做罷。現在決定將這些函數整理分類列出來就好。

【傳出位置】(指標不變動)
next:傳出下一個位置
back:傳出前一個位置
head:傳出頭的位置
tail:傳出尾的位置
at:傳出某位置(目前的位置為1)
skip:傳出某位置(目前的位置為0)

【移動位置】(指標會變動)
++:傳出目前位置,再移動到下一個
--:移動到前一個,再傳出目前的位置

【取得資訊】
index?:目前位置索引值
offset?:兩個索引值的差距
length?:剩下的個數
empty?:是否剩下的個數為0
head?:是否為頭
tail?:是否為尾
past?:是否超過尾端

【取得元素】
first:第一個元素
last:最後一個元素
pick:注意0和負的時候,R3.0和R2.x的傳出值不同。
second ... tenth:第n個元素
也可以使用path來取得元素,效果同pick

【取得元素+移動位置】(指標會變動)
first+:取得目前位置的元素,並移動到下一個位置

【取得元素+移動位置】
generate-cycle:製作循環的函數
generate-series:製作不循環的函數(cf. first+)

【取得元素+移除元素】(內容會變動)
take: first + remove

【插入元素】
insert
append(repend)

【移除元素】
remove(效果同take,但傳出值不同)
clear
remove-each

【改變】
poke
change

【複製】
copy

【尋找】
find
maximum-of
minimum-of
replace

【排列】
reverse:顛倒
random:亂排
sort:排序

【交換】
swap:交換兩個序列位置內的first元素

【建立】
array

【其他】
alter可能在3.0版中會移除。

2008年4月5日

REBOL Application Marketplace?

我記得Carl似乎曾有一個類似REBOL 3.0 Application Online Marketplace的提議,當然如果此計畫要成形,最快也會是在2009。我觀察到今年(2008)Marketplace概念有一點小熱門,包括Apple iPhone、U3、VMware、Windows、Adobe AIR、SalesForce AppExchange都有意這麼搞,或者已經在這麼搞了。連最近積極和我聯繫的一家北京軟體公司,也在做類似U3 + VMware的平台。我最近在iThome【言程序】發表了一篇Marketplace相關的文章,你可以參考。

2008年4月3日

Series函數:取得資訊

index?用來取得目前位置索引值。

offset?計算兩個索引值的差距。其實相當於「第二個引數的索引值」減掉「第一個引數的索引值」。

想知道是否在頭的位置,使用head?。

想知道是否在尾的位置,使用tail?。

length?計算剩下的個數(目前的位置算在內,但tail不算)。

想知道是否為空,可以判斷是否為尾端,或者length?是否為零,或者直接使用empty?。雖然tail?和empty?的作用一樣(事實上,empty?和tail?是完全相同的函數,所以「same? :empty? :tail?」會得到「true」),但是意義不同,寫程式時最好選擇正確意義者,以方便他人閱讀理解。

想判斷是否超過尾端,用past?。補充說明:為何會超出尾端?

(待解問題:用empty?判斷指向past的位置,會如何?)

Series函數:遞增與遞減



Series可以使用遞增(++)和遞減(--)函數,這兩個函數都會改變指標。++會傳出目前位置,再移動到下一個,新位置和傳出的位置是不一樣的。--是移動到前一個,再傳出目前的位置,新位置和傳出的位置是一樣的。為何兩者的作法不一致(++先傳出再移動,--先移動再傳出),這個問題留待迴圈的文章中解答。

2008年4月2日

Series函數:傳出新位置,指標不變動

Next用來傳出下一個位置,參數指標的位置不變動。

Back用來傳出前一個位置,參數指標的位置不變動。

At傳出某位置,目前的位置視為「位置1」。

Skip傳出「略過多少格位置」之後的位置。 Skip和At會有一格的差距。

At和Skip的引數都可以為負的值,這個時候,這兩個函數的結果完全一樣。


Head會傳出頭部的位置。

Tail會傳出「尾部」的位置。所謂的「尾部」,是指「最後一個元素的下一個」位置,而不是最後一個元素的位置。

不管用什麼函數,當意圖往前移動到超出邊界,會停留在頭部的位置;意圖往後移動超出邊界,則會停留在尾部的位置。

2008年4月1日

關於Unicode的一些判斷函數

utf?函數需要一個binary!當參數。根據此binary的BOM(byte order mark)來做判斷,如果傳出值的絕對值是8,則表示UTF-8;如果傳出值的絕對值為16,則表示UTF-16;如果是Big-Endian,則傳出值為正;如果為Little-Endian,則傳出值為負。 例如:

>> utf? #{EF BB BF}
== 8
>> utf? #{FE FF}
== 16
>> utf? #{FF FE}
== -16
>> utf? #{00 00 FE FF}
== 32
>> utf? #{FF FE 00 00}
== -32

如果binary不是上述的開頭,會得到0的傳出值,表示無法識別。

latin1?需要一個引數,可以是泛字串或字元或整數(表示Code Point)。如果code point都小於256,則傳出true;否則傳出false。latin1?未來有可能改成latin-1?。

ascii?函數和latin1?完全一樣,但用來判斷code point是否小於128。

關於Unicode的BOM,可以參考這篇FAQ的解釋以及這篇Wiki。REBOL的UTF?只用來判斷8, 16, 32的LE和BE的BOM,不支援其他BOM(因為其他BOM很少有人用)。

什麼是action?

action是所有資料型別都必備的基本原生函數。你可以透過下面的方式取得完整的action列表:

>> probe system/catalog/actions

每個資料型別都有一個表格(類似C++的Virtual Table),記錄此型別專屬的所有action函數。目前每個資料型別的action表格內都有68個函數。

>> length? system/catalog/actions

== 68

當你使用action函數時,此action函數會根據參數的資料型別,來決定呼叫那個表格內的對應函數,其實這是一種Polymorphism。例如,當你呼叫subtract時,它會根據參數是整數或日期或其他,來決定使用哪一個資料型別action表格內的subtract函數。

如果你使用下面的方式觀察,你會發現實際上列出來的action!不只68個:

>> ? action!

那是因為許多action都可以輕易處理掉,不需要在action表格中準備特殊的函數。這類的action函數以查詢型別的函數為大宗,例如integer?、string?。

關於集合的基本運算



REBOL有一個unique函數,可以將一個集合內重複出現的元素移除,例如:

>> unique [1 2 1 2 3]
== [1 2 3]

REBOL有四個函數,可以進行兩個集合的計算,這四個函數分別是union、intersect、exclude、difference,其作用如圖所示。 使用union、intersect、exclude、difference所得到的結果,一定不會有重複的元素,感覺就像是使用unique處理過一樣。這是因為,一旦使用這四個函數,就等於是將引數視為「集合」,而數學上對集合的定義,本來就是不可以有重複的元素。例如:

>> union [1 2 1] [1 3 1]
== [1 2 3]

上述五個函數都具有/skip和/case兩個修飾(refinement)。/case表示區分大小寫(不加上此refinement則不會區分大小寫)。/skip需要一個整數引數n,表示每n個元素被視為一筆記錄。

這裡所謂的集合,包括了string!、block!、以及bitset!。

bitset本來就是不會重複的字元集合,所以對bitset使用unique函數並不會產生任何作用。這五個集合函數作用在bitset上的時候,不可以搭配/case或/skip。這五個集合函數用在string時,不可以搭配/skip。
請注意,unique會造成原本集合的改變,但union、intersect、exclude、difference則不會破壞原來的集合。
另外,complement函數可以用來為bitset進行反相,但是目前alpha版尚未定義實際的作法。

REBOL 3.0進度:Linux and MacOS X

幾個小時前,REBOL公司推出了Linux和MacOS X平台上的core alpha測試版(螢幕截圖請見Henrik的貼文)。加上原本的Winodws版,現在已經有三個OS平台的版本了。

另外,REBOL公司預計在四月釋出REBOL 3.0 beta核心,供大眾測試。