2008年3月31日
logic!資料型別的位元欄位
由於電腦資料處理時,最小的單位是位元組(8個位元),而8個位元能夠表達的資料有2的8次方(256)種,所以只用來表達logic!實在有一點浪費,但這也是無可奈何的事。
REBOL 3.0充分運用原本浪費的空間,來做更豐富的表達。logic!可以被視為有許多位元欄位(bit field),每個欄位都可以有自己的名稱:
>> paradigm: make logic! [ imperative object-oriented functional logical ]
== false
>> paradigm/imperative: true
== true
>> paradigm/functional: true
== true
>> mold/all paragigm
{#[logic! 5 [imperative object-oriented functional logical]]}
為何內部的值會是5?因為imperative(最低的位元)和object-oriented(第三低的位元)為true,所以值為#{00000101},也就是5。
邏輯值的位元欄位可以超過8個,例如:
>> paradigm: make logic! [ b1 b2 b3 b4 b5 b6 b7 b8 b9 b10 ]
== false
由於只要有任何一個位元欄位為true,整體邏輯值就為true,所以位元欄位可以用來取代OR運算子或ANY函數,例如:
if any [b1 b2 b3 b4 b5] [
do-something
]
改寫成:
flags: make logic! [b1 b2 b3 b4 b5]
...
if flags [
do-something
]
2008年3月30日
Reflection
>> reflect system 'words
== […]
>> reflect system 'values
== […]
上面的兩個例子,意思是列出system物件的words,以及列出system物件的values。
除了words和values,reflect還接收哪些單字當作第二個引數?這些單字全都列在system/catalog/reflectors中:
>> system/catalog/reflectors
== [ spec body words values types title ]
除了使用reflect函數之外,也可以使用速寫的版本,包括了spec-of、body-of、words-of、values-of、types-of、title-of。也就是說「reflect system 'values」和「values-of system」作用是一樣的。
這些函數適合用在IDE和自動測試程式中,除此之外,平常應該是不會用到。
REBOL 3.0未來將可以支援UCS-4
另外,新版的REBOL提供了原生函數,可以幫助我們判斷字元或字串是否為ASCII(0~127),或者是否為Latin-1(0~255)。
2008年3月29日
千變萬化的REBOL Host
你可以寫出各種作業系統的Host,這麼一來,REBOL程式就可以在該作業系統上執行。REBOL公司預計會提供Windows、MacOS、Linux、BSD等主流作業系統的Host。(目前2.x版就支援上述的平台。)
REBOL公司應該也會推出瀏覽器插件(Plug-in)版本的Host,如此一來,REBOL程式就可以像Sliverlight或Flash一樣,被嵌入網頁內。(2.x版已經有支援瀏覽器插件,請見這裡。)
Host也可以寫成Web伺服器的模組,例如Apache MOD,讓REBOL程式和伺服器之間的整合更好,適合當作Server-side的編劇環境。
可以預期會有人幫REBOL做出Windows Services,使得REBOL可以寫出「常駐程式」(有人開發出2.x版的Windows Services,請見NT-Services Support Library)。
最棒的是,你可以讓你自己的原生程式當作REBOL的Host,等於是把REBOL嵌入你的程式中。
2008年3月28日
REBOL 3.0進度
在REBOL公司的網站改版之前,REBOL 3.0有一個暫時性的網址。官方最新的消息都會公布在這裡。
根據該網站的說明,最近2.x版的維護已經告一個段落,重點再度回到REBOL 3.0。AltME社群內部的記錄顯示,REBOL公司已經修正我之前提出的某些Bug,也將Unicode核心版本釋出給所有的Alpha成員。另外REBOL公司也製作一套自動Test Case產生器,來幫忙找出Bug。
2008年3月27日
預測3.0正式版的推出日期
2008年3月21日
REBOL 3.0的開放源碼模型
2008年3月19日
Jerry Tsai’s “Size Does Matter” Chart, 2008 Edition, Service Pack 1
有讀者告訴我,其實197MB裡面同時包含了64位元和32位元的.NET執行環境,儘管如此,我依然無法想像為何會包成這麼大一包。我印象中,不管32位元的CLR或64位元的CLR,都是使用32位元的Managed PE檔。這就好像不管32位元的JVM或64位元的JVM,都是使用相同的.class檔(Java Bytecode)一樣。
.NET體積雖然大,但是有將Enterprise的程式庫放進去。我列出的JRE體積雖小,但是只有J2SE,並非J2EE。Adobe AIR雖然一出生就11MB,感覺很大,但它內建資料庫、和網頁展現引擎,這是其他執行環境(Java和.NET)所沒有的。所以本來體積的比較,就不會太公平。
所以體積的比較,只能讓你瞭解大概的狀況,軟體是不是真的「虛胖」,你必須分析它的功能才知道,這工程浩大,我就無法代勞了。
2008年3月18日
Size Does Matter, 2008 Edition
2008年3月17日
推薦一本自然語處理的好書
REBOL的命名慣例
- 型別名稱後面加上驚嘆號,例如「integer!」、「char!」、「block!」。
- 只詢問資訊,沒有命令動作,也不會更動任何資料的函數,名稱後面加上問號「?」,例如「length?」、「type?」、「exists?」。
- 一個單字如果由多個字組成,則字和字之間使用-當連接符號,不使用底線當連接符號,例如「to-local-file」、「split-path」、「make-dir」。
- 目的與作用一樣,只是多了一點小變化,則名稱也多了一點小變化,通常是在名稱後面加上「*」或「+」或「~」,例如「first」與「first+」、「system/options/locale」與「system/options/locale*」。
2008年3月15日
Size Does Matter
這是我好幾年前整理出來的一張圖,其中列出來的許多Script語言可能都沒有包含GUI套件,如果把GUI套件也加上去的話(它們使用的GUI套件體積都很大),原本不小的體積就會更龐大了。
經過這些年,這些執行環境本身都變大許多,例如.NET到了2.0版,已經膨脹到約50 MB,至於.NET 3.5有多大,我已經懶得去查了。但是最近推出alpha的REBOL 3.0,卻依然維持相當小的體積,只有數百KB,正式版推出時,應該也不會超過1MB。在這1MB之內,所有的功能(包含GUI),一應俱全。
我非常討厭肥大的軟體,你可以去閱讀我的這一篇文章「軟體的病態性肥胖」。
為各種資料型別分類
分門別類,是一種整理知識的表現。對REBOL程式員來說,為各種資料型別(datatype)分類相當重要,因為相同種類的資料型別,往往會有相當類似的操作方式,甚至可以使用完全一樣的函數來進行操作。如果你知道每個型別屬於哪一類,那麼在寫REBOL程式時,很容易就可以發揮聯想,猜測有哪些函數可以用。
我們可以利用兩種方式,看看REBOL內部是如何為這些資料型別分類的:
- typeset!
- spec-of
【typeset】
typeset!(資料集)本身就是一種資料型別,用來將某些資料型別結合起來,成為一種「類似」資料型別的新組合。你可以利用下面的方式,看看REBOL預先定義哪些資料集:
>> ? typeset!
你會看到上面列出8種資料集,分別是any-block!、any-function!、any-string!、any-type!、any-word!、number!、scalar!、series!。你可以再次利用?函數,來看它們各自的詳細說明,例如:
>> ? number!
NUMBER! is a datatype of value: make typeset! [integer! decimal! [percent!]
意思是,NUMBER!是由integer!、decimal!、percent!這三種型別所組成的資料集。
下面就這八種資料集做整理:
Number! 有三種
- Integer! (整數)
- Decimal! (小數)
- Percent! (百分比)
Scalar!
- Integer! Decimal! Percent! (同Number!)
- Money! (精準數)
- Char! (字元)
- Pair! (值對)
- Tuple! (值組)
- Time! (時間)
- (註:我認為應該也要包含Date!)
Any-Word! (泛單字)
- Word! (單字)
- Set-word! (設字)
- Get-word! (取字)
- Lit-word! (原字)
- Refinement! (修飾)
Any-string! (泛字串)
- String! (字串)
- Binary! (二元)
- File! (檔案)
- Email! (電郵)
- Url! (網址)
- Tag! (標籤)
- Issue! (期號)
- (註:我認為應該也要包含Bitset!)
Any-block! (泛區塊)
- Block! (區塊)
- Paren! (括號區塊)
- Map! (對應表)
- Path! (路徑)
- Set-path! (設徑)
- Get-path! (取徑)
- Lit-path! (原徑)
Series! (系列)
- 包含「泛字串」與「泛區塊」的全部類別
- Bitset! (位元集)
- Vector! (向量)
- Image! (影像)
Any-function! (泛函數)
- Native! (原生函數)
- Action! (動作函數)
- Routine! (常式)
- Rebcode! (彙編碼)
- Op! (運算子)
- Closure!
- Function! (普通函數)
Any-type!
- 全部(50+個)資料型別
【spec-of】
除了上述的方式,利用spec-of,搭配probe,也可以看出各種類別的分類,而且更全面。 作法:
>> probe spec-of block!
下面列出用這種方式觀察出來的分類。
Block
- Block!
- Get-path!
- Lit-path!
- Map!
- Paren!
- Path!
- Rebcode! (註:這有點怪)
- Set-path!
- Struct! (註:這有點特別)
Function
- Action!
- Closure!
- Function!
- Native!
- Op!
- Routine!
Internal (內部使用)
- End!
- Frame!
- Handle!
- Library!
- Unset!
Object
- Error!
- Module!
- Object!
- Port!
- Task!
- Utype!
Opt-Object
- Event!
- Gob!
- Typeset!
Scalar
- Char!
- Date!
- Decimal!
- Integer!
- Logic!
- Money!
- None!
- Pair!
- Path!
- Percent!
- Time!
- Tuple!
String
- Binary!
- Bitset!
- Email!
- File!
- Issue!
- String!
- Tag!
- Url!
Symbol
- Datatype!
Vector
- Image!
- Vector!
Word
- Get-word!
- Lit-word!
- Refinement!
- Set-word!
- Word!
String和Binary之間的轉換
2008年3月14日
REBOL解譯器的執行方式
這篇文章相當重要,只要你懂這篇文章,REBOL剩下的主題,都不會太難。本文章中提到的計算、執行、估算、求值,都是指一樣的概念。
【ANY-WORD】
有的word有綁著(bind)一個值,計算這類的word,就相當於計算它所綁的值。例如:
>> pi
== 3.141592653589793
有的word沒有綁著一個值,計算這類的word,就會得到錯誤訊息。例如:
>> vista
** Script error: vista has no value
將一個word前面加上一個單引號('),就變成lit-wird。如果執行一個lit-word,就會得到它對應的word。例如:
>> 'pi
== pi
>> 'vista
== vista
將一個word後面加上一個冒號(:),就變成set-word。如果計算一個set-word,就會先計算後面的值,然後把這個值綁到word。例如:
>> pi: 3.14
== 3.14
>> pi
== 3.14
你可以把冒號想像成「等於」,所以「pi: 3.14」的意思就是「pi = 3.14」。原本pi被綁到一個很精確的值(3.141592653589793),現在被改成綁到3.14。
執行set-word之後,新的值會再度傳出。如果想一次將多個word設定成相同的值,可以利用這一點,例如:
>> a: b: c: 0
現在a b c都被設定為(綁到)0。
將一個word前面加上一個冒號(:),就變成get-word。如果計算一個get-word,就會得到它所綁的值。例如:
>> :pi
== 3.14
你可能覺得很奇怪,執行get-word和執行word得到的結果不是一樣嗎?
>> pi
== 3.14
雖然這個例子的結果一樣,但是意義不一樣。計算get-word,會取出所綁的值(3.14),直接傳出來;計算word,則多了一個步驟:先取出所綁的值(3.14),然後再計算這個值。只不過3.14計算之後剛好還是3.14。
當word被綁到函數的時候(REBOL有七種函數,請見「各種函數的區別」一文),就不一樣了:
>> now
== 14-Mar-2008/0:06:21+8:00
>> :now
== native!
now被綁到一個native函數,計算「:now」的值,只會得到這個函數,所以你會看到上面的例子寫「== native!」;計算now的值就會造成計算此native函數,因而得到現在的時刻。
將一個word前面加上一個斜線(/),就變成refinement。如果計算一個refinement,就會得到原封不動一樣的refinement。例如:
>> /year
== /year
refinement主要用在函數中,等一下就會看到。
【ANY-PATH】
有一種和word很像的東西,名為path。它由多個word串接起來的,word之間利用「/」當分隔符號。例如:
>> system/version
== 2.99.4.3.1
執行此path,得到的值是「2.99.4.3.1」(整個是一個值)。
path一樣有對應的lit-word、set-word、get-word。例如:
>> 'system/version
== system/version
>> system/user/name
== none
>> system/user/name: "Jerry Tsai"
== "Jerry Tsai"
>> system/user/name
== "Jerry Tsai"
>> :system/user/name
== "Jerry Tsai"
【函數】
前面提到過,如果某word或path被綁到一個函數,那麼計算此word或path就等於計算此函數:
>> now
== 14-Mar-2008/0:06:21+8:00
某些函數word可以加上refinement。例如:你只想取得現在的年份,你可以在now函數的後面,緊接著「/year」refinement:
>> now/year
== 2008
某些函數需要引數(argument),例如「length?」後面可以接著一個字串,傳出字串長度:
>> length? "Jerry"
== 5
大多數的函數,都會先計算出後續的引數,然後才執行函數。以上面的例子來說,"Jerry"計算的結果還是"Jerry",然後傳進length?當引數。下面是另一種寫法:
>> name: "Jerry"
== "Jerry"
>> length? name
== 5
name會先被執行,得到"Jerry"的值,然後把"Jerry"傳進length?當引數。
少部份的函數(例如help、source),不會先估算後續的引數,而是直接將後面的值傳入函數中。例如:
>> help 3.14
3.14 is a decimal
>> help pi
PI is a decimal of value: 3.14
為何第二個訊息會出現PI?因為傳進help函數的引數,是一個word,其值為pi。再看另一個範例:
>> now
== 14-Mar-2008/0:06:21+8:00
>> help 14-Mar-2008/0:06:21+8:00
14-Mar-2008/0:06:21+8:00 is a date
>> help now
USAGE …
「help now」列出了now的使用方式,而不是「… is a date」,這是因為help不會先去估算now的值,而是直接把now這個單字當作值,傳入help中。
那些函數所需要的引數是不會先估算的?這類的引數相當少,而且幾乎都是用在shell中做一些輔助查詢。
常常會一個函數執行到一半,就要跳去執行另一個函數。例如:
>> length? to-local-file what-dir
這個意思是取出目前的目錄(what-dir),將它轉成作業系統的檔案字串(to-local-file),然後計算長度(length?)。感覺好像運算次序變成由右到左,其實還是由左到右。先計算length?,由於length?是一個函數,它需要一個引數,所以從後面找來一個引數,此引數為to-local-file。剛好to-local-file也是一個函數,也需要一個引數,所以從後面取得what-dir的估算結果。有了what-dir的估算結果當引數,to-local-file就可以順利被估算,得到一個結果;有了to-local-file的估算結果當引數,就可以計算length?。
【op】
你可以用下面的方式表達「一加二」:
>> add 1 2
== 3
add是一個函數,需要兩個引數,分別是被加數與加數。最後add將計算的結果傳出來。
你可以用下面的方式表達「一加二減三」:
>> subtract add 1 2 3
== 0
subtract是「減」,後面需要兩個引數,分別是被減數與減數;其中被減數是add,而add又需要兩個引數,分別是1、2。所以「add 1 2」的結果會被當作subtract的第一個引數,最後的3就變成subtract的第二個引數。
你一定很不能接受,「一加二減三」居然要寫成「subtract add 1 2 3」,尤其是subtract居然還出現在add的前面。一個簡單的數學式子用REBOL來表達,竟會如此麻煩。所以在表達數學式子的時候,我們不喜歡用這樣的方式,我們會寫成:
>> 1 + 2 - 3
== 0
其中+與-也都是函數,這種函數稱為op(運算子),出現在兩個引數的中間。也就是說「add 1 2」相當於「1 + 2」
出了出現的位置和一般函數不一樣之外,op還有一點很特殊:一律由左到右的次序計算。例如:
>> 1 - 2 + 3
== 2
先計算「1 - 2」,得到「-1」;再計算「-1 + 3」,得到「2」。
op一律由左到右的次序計算,沒有所謂的「先乘除後加減」,例如:
>> 1 - 2 * 3
== -3
你可以利用括號 ( ) 改變次序,例如:
>> 1 - (2 * 3)
== -5
想知道REBOL有哪些op,在shell輸入:
>> help op!
來看最後一個例子:
>> divide 5 + 4 * 3 2
== 13.5
divide(除法)需要兩個引數,第一個引數是「5 + 4 * 3」,第二個引數是2;「5 + 4 * 3」的值是27,而「divide 27 2」得到13.5。
為何第一個引數是「5 + 4 * 3」,而不是「5」,因為REBOL解譯器注意到,5的後面跟著一個op,而op是一定位於兩個值的中間,所以第一個引數擴大為「5 + 4」;接下來REBOL解譯器又注意到後面又出現一個op,於是再把第一個引數擴大為「5 + 4 * 3」。
REBOL英中對照表
action: 動作 [movement] [doing]
argument: 引數 [refer] [number]
-based: 基底 [base] [base]
binary: 二元 [two] [primary]
bind(ing): 繫結 [bind] [bind]
bitset: 位元集 2x[bit] [set]
block: 區塊 [division] [block]
callback: 回呼
char: 字元 [character] [primary]
closure:
component: 元件 [primary] [thing]
compile(r): 編譯(器)
concurrent: 共時
context: 脈絡
datatype: 資料型別 2x[data] 2x[type]
date: 日期 [day] [a period of time]
decimal: 小數 [little] [number]
dialect: 方言 [local] [language]
email: 電郵, 電子郵件 [electronic] [mail]
-er: 者 員(人), 器 子(程式)
error: 錯誤 [wrong] [mistake]
evaluate: 估算 [estimate] [compute]
event: 事件 [affair] [thing]
export: 匯出 [flow] [out]
file: 檔案 [file] [case]
frame: 框 [frame]
function: 函數 [letter] [number]
get-path: 取徑 [get] [path]
get-word: 取字 [get] [word]
gob: 圖形物件 2x[graphics] 2x[object]
handle: 代碼 [surrogate] [code]
image: 影像 [image] [image]
import: 匯入 [flow] [in]
integer: 整數 [whole] [number]
interface: 介面, 界面
interpret(er): 解譯器
issue: 期號 [issue] [code]
library: 程式庫 2x[program] [base]
list: 清單
lit-path: 原徑 [original] [path]
lit-word: 原字 [original] [word]
logic: 邏輯 [this is transliteration]
map: 對應, 對應表 [pair] [answer]
mezzanine: 中層 [middle] [layer]
module: 模組 [mold] [combination]
money: 錢 [money]
native: 原生, 原生函數 [original] [living]
none: 空, 無 [void]
object: 物件 [thing] [thing]
op: 運算子 2x[operate] [-er]
-or: 者 員(人), 器 子(程式)
-oriented: 導向 [direct] [direction]
pair: 對, 值對 [pair]
parameter: 參數 [refer] [number]
paren:
parse: 剖析 [dissect] [analyze]
path: 路徑 [path] [path]
percent: 百分比 [100] [division] [ratio]
profile: 特徵分析(v), 特徵描述(n)
program: 程式(n), 編程(v)
probe: 探測
prototype: 原型
plug-in: 插件 [plug] [thing]
port: 埠, 港埠 [port]
rebcode: 彙編碼 2x[assembly] [code]
refinement: 修飾 [decorate] [decorate]
routine: 常式 [common] [formula]
set-path: 設徑 [set] [path]
set-word: 設字 [set] [word]
scalable: 規模可變
script: 劇本(n), 編劇(v)
stack: 堆疊 [stack] [stack]
string: 字串 [character] [string]
struct: 結構 [knit] [compose]
tag: 標籤 [mark] [label]
task: 任務 [appointment] [business]
thread: 線程
time: 時間 [time] [period of time]
trace: 蹤跡(n) 追蹤(v)
transaction: 交易
tuple: 值組 [value] [combination]
typeset: 型別集 2x[type] [set]
Unicode: 統一碼 2x[unified] [code]
unset:
url:
utype: 自訂型別 [oneself] [define] 2x[type]
vector: 向量 [direction] [quantity]
VID: 視覺介面方言 2x[visual] 2x[interface] 2x[dialect]
word: 單字 [single] [word]
2008年3月13日
把REBOL當Shell用
所謂的Shell,就是圍繞在OS核心外圍的使用者介面,你可以參考「當劇本遇上殼」這篇文章對Shell的說明。
本文章介紹一些常用的函數與用法,讓你可以將REBOL當作Shell,用來對OS做一些基本的檔案操作。
【目前的目錄】
如果你想知道目前的工作目錄為何,你可以利用what-dir函數,如下:
>> what-dir
== %/c/Documents%20and%20Settings/Jerry%20Tsai/桌面/
「==」表示前面的函數有傳出值,其值為「%/c/Documents%20and%20Settings/Jerry%20Tsai/桌面/」。
你也可以用pwd取代what-dir,效果完全一樣:
>> pwd
== %/c/Documents%20and%20Settings/Jerry%20Tsai/桌面/
REBOL的檔案表示方式,依照下面的規則:
- 開頭使用「%」
- 目錄的分隔符號使用「/」
- 中間如果有特殊字元,則使用「%」後面接著兩個十六進位數字,代表該特殊字元的編碼。以這裡的例子來說,空白的值,在ASCII編碼是十六進位的20。所以寫成%20
- 如果是目錄,則最後是「/」
- 如果是絕對路徑,則開頭的「%」後面會接著一個「/」。如果是相對路徑,則開頭的「%」後面不會出現一個「/」。
【檔案的轉換】
如果你對於上面描述的檔案規則覺得不習慣,可以利用to-local-file,將what-dir傳出的檔案轉成作業系統慣用的格式,作法如下:
>> to-local-file what-dir
== "C:\Documents 20and 20Settings\Jerry Tsai\桌面\"
因為to-local-file的傳出值是字串不是檔案,所以前後加上雙引號「"」。有一個函數和to-local-file做的事剛好事相反的,可以把作業系統檔案字串,轉成REBOL檔案,此函數名為to-rebol-file,範例如下:
>> to-rebol-file "C:\Program Files\"
== %/C/Program%20Files/
【改變目錄】
你可以使用change-dir(或cd)函數,改變目前的目錄,例如:
>> cd %/c/
>> pwd
== %/c/
你也可以利用相對路徑的表示方式(也就是開頭的「%」後面不寫「/」),例如:
>> pwd
== %/c/
>> cd %Program%20Files
>> pwd
== %/C/Program%20Files/
有兩個特殊的相對路徑表示方式:「%.」表示目前的目錄,「%..」表示往上一個目錄。依此類推,「%../../表示往上兩層目錄」。下面是一個範例:
>> pwd
== %/C/Program%20Files/
>> cd %..
>> pwd
== %/c/
【製造目錄】
你可以使用make-dir(或mkdir)函數,製作新的目錄,例如:
>> mkdir %abc/
這表示在目前的目錄下,建立一個abc目錄。再看一個例子:
>> mkdir/deep %/c/rebol/my-script/
這裡的mkdir後面緊接著出現「/deep」,意思是:在建立此目錄的過程中,如果有其他的目錄尚未建立,就一併建立。所以如果%/c/rebol/尚未存在,就會先建立%/c/rebol/,然後再建立%/c/rebol/my-script/。
像這種函數後面加上的修飾,我們稱為refinement。
【列出檔案】
你可以使用list-dir(或ls)函數,將某目錄下的檔案列出來,例如:
>> ls %/c/
如果後面沒有寫目錄,預定就是目前的目錄(%.),例如:
>> ls
list-dir(與ls)可以使用下面的refinement:
/l:表示每個檔案用一行顯示
/f:只列出檔案,不列出目錄
/d:只列出目錄,不列出檔案
/r:列出此目錄以及底下所有子孫目錄內的檔案
例如:
>> ls/l/r
當同時使用兩個以上的refinement時,順序無所謂,所以「ls/l/r」和「ls/r/l」是完全一樣的效果。
【取得檔案資訊】
你可以利用「modified?」取得檔案最後修改時間,用「size?」取得檔案大小,用「dir?」得知否為目錄(而非檔案)。例如:
>> modified? %/c/rebol/core.exe
== 5-Mar-2008/6:31
>> size? %/c/rebol/core.exe
== 219136
>> dir? %core.exe
== false
2008年3月10日
各種函數的區別
- Function!
- Closure!
- Rebcode!
- Native!
- Action!
- Op!
- Routine!
屬於Function!、Closure!、Rebcode!型別的函數,都可以利用source函數來觀看其源碼(source code)。例如,在REBOL console中輸入「source what」,就可以看what的源碼:
屬於Native!、Action!、Op!型別的函數,都「無法」利用source函數來觀看其源碼,因為它們的程式是用C語言寫的,經過編譯。至於Routine!,是用來連接到外部動態連結程式庫的函數,REBOL 3.0尚未決定是否要支援Routine!。
Native!、Action!、Op!都是REBOL系統內部內建的函數,我們無法在REBOL程式中自行定義這些函數。Routine!只是用來和外部的程式做連結,我們也無法在REBOL程式中定義它的邏輯。我們在REBOL程式中,能夠自行定義的函數,只有Function!、Closure!、Rebcode!。
一般來說,我們寫REBOL程式時,定義的函數是Function!。如果希望執行過後,函數內的context能夠保留,就不要使用Function!,改用Closure!,缺點是效率會比較差。如果希望函數的執行速度提高,就不要使用Function!,改用Rebcode!,但是Rebcode!不是使用REBOL語言,而是使用Rebcode方言,相當於REBOL虛擬機器的組合語言。使用Rebcode!的缺點是,程式比較不容易讀寫(因為Rebcode方言比REBOL語言更低階的緣故)。
Native!和Action!的差別只會影響REBOL內部,和我們沒有關係,所以可以不用理會它們的差異。Op!比較特別的地方在於,它是中序的(infix),而其他六種函數都是前序的(prefix)。
閱讀REBOL文件或書籍時,請注意。當提到「函數」時,有可能泛指所有的七種函數,也有可能單指function!,必須利用前後文來判斷為何者。如果提到mezz,則一定指function!。如果提到「原生函數」,有可能泛指native!、action!、op!,也有可能單指native!。
使用Windows Console
REBOL預計會有兩個Console,一個是文字模式的DevStdIO,一個是圖形模式的DevConsole。目前已完成的只有DevStdIO。在Windows作業系統上,DevStdIO也就是Windows console。因此,你需要知道Windows Console的基本用法,整理如下:
- 左右方向鍵:在目前的命令列左右移動編輯游標。
- Ctrl+左右方向鍵:按住Ctrl鍵不放開,再按下向左方向鍵,或向右方向鍵,在目前的命令列左右移動編輯游標,一次移動一個word,而不是一個字元。
- Home:將編輯游標移動到目前命令列的開頭。
- End:將編輯游標移動到目前命令列的尾端。
- 上下方向鍵:調出歷史命令(之前輸入過的命令)。
- 插入(Ins)鍵:在字元插入與字元覆蓋(overwrite)模式之間切換。
- 刪除(Del)鍵:刪除游標後的字元。
- 倒退(Backspace)鍵:刪除游標前的字元。
- F7:在文字視窗內,躍出一個「命令歷史清單視窗」(如上圖所示),然後使用上下鍵選取命令,最後按下Enter執行命令。除了F7,我發現F2、F3、F4、F9也有特殊功能。
- Ctrl+空白鍵:中文輸入切換。
- 用滑鼠拖檔案進來:可以輸入該檔案的全名。
可惜的是目前還不能使用tab,進行補完(completion)。
想要離開此console,使用q或quit函數即可,如下所示:
>> quit
2008年3月9日
DevCon 2008在布拉格的夏天
REBOL DevCon研討會第一次是2005年在美國,第二次是2007年在法國,第三次就是今年。地點的選擇顯然是考慮到使用者的多寡。目前REBOL開發者最多的國家,似乎依序就是美國、法國、捷克(首都布拉格)。
今年的研討會重點應該就是REBOL 3.0。我想選擇9月的意義,或許代表9月時3.0可以正式推出。這雖然是臆測,但可能性很高。
REBOL 3.0的Unicode進度
REBOL函數的複製與否
對於大多數的物件導向語言來說(包括C++、Java、C#),實體方法(instance method)一定會被傳進一個隱匿的參數(implicit parameter),當作方法的第一個參數,此參數正是此物件實體。大多數的語言,都稱此參數為this。
在實體方法內,如果沒有指明呼叫的方法是由誰所提供,就相當於在前面加上「this.」。因此呼叫myMethod(),就相當於呼叫this.myMethod()。語言這麼設計的好處是,不管new出多少個實體,這些實體方法都只需要一份,節省相當多記憶體。
REBOL物件內的函式,雖然可以使用self參考到物件本身(self類似於其他語言的this),但是self是被繫結(binding)到函式內的,並不是被當成隱匿的參數傳入的。事實上,不只self,該物件context會整個被繫結到函式內。因此,產生新物件時(REBOL產生物件的方式是「複製」),如果只有複製資料,沒有複製物件內的函式(使用COPY obj),會造成新物件的函式依然參考到舊的物件,造成奇怪的後果。如果連同函式一起複製,並將新函式重新繫結到新物件,就不會有這樣的後果(使用MAKE obj [] )。
但是這麼做會浪費相當多記憶體,所以另一種比較常見的作法是將這些函式都獨立出來,不要放在物件內。為這些函式都加上一個物件參數,好將它們要處理的物件傳遞進來。這樣的設計相當於走回C語言常用的設計方式。當然,REBOL社群會比較建議採用這種方式,因為REBOL人對於無謂的浪費是相當在意的。
2008年3月8日
我的REBOL體驗
約26年前,我寫了生平的第一個程式,當時用的語言是BASIC,電腦是台灣仿冒的APPLE II。從那個時候開始,我就斷斷續續地學習程式設計。讀中學時,我最常用的是dBase III+和Clipper。
進入大學後,我主修資訊科學(Computer Science),我覺得課堂上學習的一切知識都相當有趣。我陸續學習了C語言、x86組合語言、C++、Java。
念研究所時,我們用Java開發了一套隨選多媒體系統(Multimedia-on-Demand),並用這套系統參加比賽得到冠軍,這使得我的生活起了變化。我開始應邀為網站和雜誌寫專欄、開Java課、擔任研討會講師,這些工作使得我對於資訊新知越來越重視。我不斷地學習新知識,我說這是「未雨綢繆」。
有一天我在書局看到一本英文版的原文書,名為"REBOL: The Official Guide",好像很有趣的樣子。當時我剛好口袋有閒錢,就買了。後來我發現這本書並不好讀,於是我到REBOL.com網站,找到免費的REBOL使用手冊,於是就開始讀起REBOL使用手冊。一遍又一遍地讀完很多次之後,我大概知道REBOL是什麼了,只是沒有機會使用它。
幾年之後,機會來了。有一天,我的老闆要我寫程式做光碟檔案內容的格式轉換,而且急著當天就要結果。我於是決定不用Java,因為我評估Java會耗掉我至少兩天,根本不符合老闆的要求。我決定使用REBOL試試看。
你猜結果如何?我居然辦到了!
當時我覺得很驚喜,畢竟我可不是什麼REBOL專家,居然可以在對REBOL語言半生不熟的狀況下,寫出程式。而且REBOL開發效率還比我當時最熟悉的Java快。
這樣的經驗實在太美好了,於是我自掏腰包買了最貴的商業版REBOL,我加入REBOL討論區,我向朋友推薦REBOL,我在大學教Web Programming時,把REBOL當作課堂上主軸的語言。我甚至在我的Java書裡面放進REBOL的內容(不過這次就有一點太過份,因為有讀者反應,不瞭解為何會在Java的書內看到REBOL)。
但是REBOL只有支援SBCS字串,不支援DBCS或Unicode,所以在東亞CJK地區幾乎無用武之地。我一直在等REBOL Technologies(RT)公司修正這一點,但是一直都沒有動靜。最後,我乾脆自己來。
花很多時間解決各種問題,後來我做到了,終於可以讓REBOL呈現Unicode。不過我的解決方案還是不理想,問題主要是在效率和字串剖析方面,這些都需要從REBOL核心去處理,不是我能解決的。幸好RT公司決定開始打造3.0版的REBOL,而且要在REBOL 3.0中支援Unicode。
有了Unicode、REBOL/services、Dialecting、Multitasking以及其他的好東西,REBOL 3.0的威力變得相當強大。每次一想到這裡,就覺得很興奮。
這些年的抱怨與等待終告結束,REBOL 3.0已經登場,Let's code。
2008年3月6日
用REBOL 3.0列出Unicode字元表
2008年3月5日
REBOL/core Unicode新版本釋出
這個版本修正了一些重大的錯誤,我這兩天有空就會開始測試!