2008年3月31日

logic!資料型別的位元欄位

大多數的語言都會有一種只能表示真(true)或假(false)的資料型別,有的語言稱此型別為boolean,有的稱為bool,REBOL稱它為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

最新版的REBOL有一個新的reflect函數,利用它可以得知某值(通常是物件、模組、或函數)的內部資訊,此函數用來取代舊版REBOL的first、second、third。reflect函數用法如下:

>> 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 3.0支援Unicode,內部使用UCS-2(也就是16位元)的方式記錄資料,已經相當夠我們使用。在REBOL 3.0的一切都穩定之後,REBOL公司不排除特別為中文的REBOL使用者編譯一套UCS-4(也就是32位元)的版本(只需要改變一下編譯時的設定即可)。如此一來,蒙古文,藏文,以及相當罕用的中文特殊字,都可以支援。

另外,新版的REBOL提供了原生函數,可以幫助我們判斷字元或字串是否為ASCII(0~127),或者是否為Latin-1(0~255)。

2008年3月29日

千變萬化的REBOL Host

REBOL將與系統相關的部分,獨立出來,放在Host。Host的部分是開放源碼的,任何人都可以幫助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日

REBOL教學影片

剛剛在REBOL部落客Henrik的網站發現一篇貼文,提到Nick Antonaccio有製作許多REBOL教學影片,放在YouTube上,你可以去瞧瞧。完整的影片清單在這裡。影片中,Nick打字的時候,鍵盤發出的聲音都被錄進去,好大聲呀 ...

預測3.0正式版的推出日期

今年預計9月舉辦DevCon,我之前據此推測此時會推出REBOL 3.0正式版,但是我現在要修正我的看法。根據現在尚缺的功能,以及RT公司目前的工作量,還有「其他權威人士」的預測,我認為REBOL 3.0正式版有可能拖到2009年才會出現。唉!

2008年3月21日

REBOL 3.0的開放源碼模型


REBOL 3.0採用混合式的開放源碼模式,共分成四個部分:
  1. Host的部分開放,這部分是和OS相關的抽象層,源碼是C語言。
  2. 核心(core)的部分不開放,由REBOL公司負責維護。如果擔心因此無法獲得保障,可以向REBOL公司取得核心源碼的授權。
  3. 內部元件(internal components)是標準的元件,這部分的源碼開放,而源碼可能是C也可能是REBOL。
  4. 外部插件(external plug-in)是REBOL開發者可以自行擴充REBOL的部分。至於源碼是開放或封閉,C或REBOL,加密或不加密,免費或收費,則由插件開發者自行決定。

2008年3月19日

Jerry Tsai’s “Size Does Matter” Chart, 2008 Edition, Service Pack 1

我其實之前也在懷疑,.NET 1.1「才」23MB,怎麼.NET 3.5會躍升到197MB,裡面是裝鉛塊了嗎?不過我自從這幾年人變老之後,已經沒有以往追根究底的精神,我懶得去分析這驚人的197MB成分為何。

有讀者告訴我,其實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


我承認在「Size Dos Matter」一文中,資料有些舊了,所以剛剛花了一點時間重繪這張圖,移除大家不熟悉的LISP,新增剛推出的Adobe AIR。

方塊內所標示的數字,是各種語言執行環境的體積MB數。為了要有一致的比較基準,這裡的軟體都一律是Windows平台上最新版,且是普遍使用的版本(例如Java使用的是Sun的版本,Perl使用的是ActivePerl的版本)。

這只是單純的體積比較。各種語言執行環境的能力(例如GUI、資料庫、Web框架、網頁展現引擎)不在這裡考量之列。

2008年3月17日

推薦一本自然語處理的好書


如果你對自然語處理感興趣,想瞭解如何寫出相關的程式。我推薦這本書,由James Allen教授著作的「Natural Language Understanding, 2nd Ed.」。雖然這是13年前的舊書,但內容還是很實用,就怕這本書絕版不容易找到了。
REBOL相當適合用來寫自然語處理的程式。

馬賽克與柔邊

剛剛寫了一篇短文,內容請見 mosaic and anti-aliasing

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內部是如何為這些資料型別分類的:

  1. typeset!
  2. 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之間的轉換



REBOL 3.0支援Unicode,字串和字元一律是Unicode。任何來自外部的資料,被視為二元,如果是文字資料,必須被解碼(decode)之後,成為Unicode字串,才能使用。字串必須被編碼(encode)轉成二元之後,被送到外部。

REBOL 2.7.6釋出

REBOL 2.x推出最新版本2.7.6,你可以到這裡下載取得最新版的SDK,或到這裡取得更多平台的Core,或找這裡下載View。建議下載View版本。完整的變動報告請見這裡

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的檔案表示方式,依照下面的規則:

  1. 開頭使用「%」
  2. 目錄的分隔符號使用「/」
  3. 中間如果有特殊字元,則使用「%」後面接著兩個十六進位數字,代表該特殊字元的編碼。以這裡的例子來說,空白的值,在ASCII編碼是十六進位的20。所以寫成%20
  4. 如果是目錄,則最後是「/」
  5. 如果是絕對路徑,則開頭的「%」後面會接著一個「/」。如果是相對路徑,則開頭的「%」後面不會出現一個「/」。

【檔案的轉換】

如果你對於上面描述的檔案規則覺得不習慣,可以利用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日

各種函數的區別



REBOL的函數(function)有7種,分別是:
  1. Function!
  2. Closure!
  3. Rebcode!
  4. Native!
  5. Action!
  6. Op!
  7. 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在布拉格的夏天

聽說今年9月要在布拉格(Prague)開研討會,我只希望機票不要太貴...。

REBOL DevCon研討會第一次是2005年在美國,第二次是2007年在法國,第三次就是今年。地點的選擇顯然是考慮到使用者的多寡。目前REBOL開發者最多的國家,似乎依序就是美國、法國、捷克(首都布拉格)。

今年的研討會重點應該就是REBOL 3.0。我想選擇9月的意義,或許代表9月時3.0可以正式推出。這雖然是臆測,但可能性很高。

REBOL 3.0的Unicode進度


你可能會想知道,REBOL 3.0目前對於Unicode的支援,進度如何了?我繪製這張圖,應該可以一目瞭然。目前Unicode的Encoder和Decoder只有支援UTF-8,這部分還有許多需要補足的地方,但是這應該不會需要太多時間。而View的方面,目前尚未開始支援Unicode,只要我們的REBOL圖學大師Cyphre有空,應該只需要幾天就可以把這部分的程式加上去。所以整體來說,目前REBOL 3.0在Uniocde的支援,已經相當接近竣工的階段。

目前我對於Unicode Alpha版的測試,已經接近尾聲,Carl應該很快就會修正完畢所有的bug,讓REBOL繼續往下一個階段走。

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字元表

REBOL 3.0 支援Unicode,而且是連console都支援Unicode,你可以在console中輸入或輸出任何Unicode字元,只要你有適當的字型,就不會有問題。

下面是一個簡短的範例,將0x0000-0xFFFF的全部Unicode列出,程式很簡單,所以我就不說明了:

for i 0 4095 1 [ 
prin rejoin [ newline to-hex/size i 3 "0 " ]
for j 0 15 1 [
prin [ to-char to-hex/size i * 16 + j 4 " " ]
]
wait .01
]

2008年3月5日

REBOL/core Unicode新版本釋出

幾個小時前,Carl釋出新版的Unicode核心(release 5)給內部測試小組。我換算一下時間,相當於當地凌晨三點 ... 他也太拼命了吧,寫程式寫到凌晨三點!

這個版本修正了一些重大的錯誤,我這兩天有空就會開始測試!

目前的構想

預計用中文寫下面幾類文章:
  1. 一系列「程式設計入門」,適合沒有程式經驗的人閱讀。
  2. 我對REBOL各個主題的研究心得。
  3. 我正在用REBOL開發的計畫。
  4. 針對Carl Sassenrath(REBOL語言設計者)最近的blog文章做說明