顯示具有 難度★★★☆☆ 標籤的文章。 顯示所有文章
顯示具有 難度★★★☆☆ 標籤的文章。 顯示所有文章

2008年6月19日

閱讀REBOL源碼時的干擾

我發現在閱讀REBOL源碼時,如果參數或修飾字(refinement)所使用的名稱和REBOL常用函數同名時,會造成我相當大的閱讀困擾。例如:

replace: make function! [[
target [series!]
search
replace
/all
/case
/tail
/local save-target len pos value do-break
][
....
]

這裡出現的replace,除了是函數名稱,也是參數;all、case、tail除了是修飾字,更是很常用的REBOL函數。我只要忘了它們是修飾字和參數,一直以函數的方式對待它們,就會造成閱讀源碼時理解力受到干擾。例如:

do-break: unless all [:break]

我一直覺得這裡的程式有錯,一直到很久以後才發現這裡的all不是函數,而是修飾字。

寫這篇blog文章,用來提醒自己和本blog的讀者(if any),閱讀REBOL源碼時,一定要注意這種狀況。

Bugfix: script?

修改後的結果如下:

script?: make function! [[
{檢查是否具有有效的劇本標頭(暫時)。}
source [file! url! binary! string!]
][
switch type?/word source [
file! [ source: read source ]
url! [ source: read source ]
string! [ source: to-binary source]
]
find-script source
]]

2008年6月18日

小心TO-BLOCK的陷阱

許多REBOL函數的參數都同時接受單一值,或多重值。當然多重值會放在block中。我們經常會需要在函數內,先將某參數化成block,然後才進行處理,這時候程式會這麼寫。

if not block? :args [args: reduce [:args]]

透過to-block(或者to block!),可以簡化上面的作法,改寫成這樣:

args: to-block :args

to-block會判斷,如果後面的參數是any-block!,則不處理,直接傳出其block形式;如果參數不是any-block!,則傳出以該參數為「唯一」元素的block。如下所示:

>> to-block 1
== [ 1 ]
>> to-block [ 1 ]
== [ 1 ]

To-block確實相當方便,但是要注意一個特殊狀況,那就是any-block!除了block!之外,還包括其他:

>> ? any-block!
ANY-BLOCK! is a typeset of value: make typeset! [block! paren! map! path! set-pa
th! get-path! lit-path! ]

因此下面的狀況固然可能非你所願,但卻是正確的:

>> to-block 'system/version
== [ system version ]

這個時候,只好回去改用一開始的寫法:

if not block? :args [args: reduce [:args]]

Bugfix: ??


??: make function! [[
{印出變數名稱,後面跟著它的鑄模值(幫助除錯用)。}
'name
][
print either any [word? :name path? name] [
repend form name [": " mold name: get :name]
] [
mold :name
]
:name
]]

上面是??函數的源碼,有個小小的bug。必須把其中的form改成mold,否則當參數是path的時候,「/」會消失,例如:

>> ?? system/version
system version: 2.100.13.3.1
== 2.100.13.3.1

另外「any [word? :name path? name]」也應該要改成「any [word? name path? name]」。

2008年6月16日

PICK is not picky

PICK可能是最不挑剔的(picky)REBOL函數,它接受的第一個參數可以是35種資料型別:

series! gob! pair! event! money! date! time! object! port! tuple ! bitset! any-function!

只有12個?別忘了,其中series!和any-function!是typeset!,將它們兩個展開之後變成

string! binary! file! email! url! tag! issue! bitset! vector! image! block! paren! map! path! set-path! get-path! lit-path! gob! pair! event! money! date! time! object! port! tuple ! bitset! native! action! routine! rebcode! op! closure! function!

共有35個資料型別。其中any-function!和object應該已經可以利用reflect(以及相關函數)取代,只是目前REBOL 3.0尚未禁止使用REBOL 2.x的pick、first等函數進行reflect。

另外有兩個可疑的資料型別,分別是event!與money!,我認為PICK不應該用來處理它們。我已經報告到Bug資料庫了。

2008年6月14日

map、remove-each、foreach

許多Functional Language(例如Erlang與F#)都具有很方便的map、filter、iter函數,可以將一個List,對應到另一個List。在REBOL 3.0中,也有類似的函數,分別是map、remove-each、foreach。比較大的差異是,其他語言是利用Higher-Order Function做到的,但REBOL是用Block做到的。

2008年6月13日

MAP-EVENT的用法


REBOL 3.0最近新增一個函數MAP-EVENT,相當好用,可以將滑鼠相關的event,從「最底層的視窗gob」對應到「最上層的gob」。新產生出來的event,其offset與gob屬性都會被修改。通常用法會是這樣:

event: map-event event

假設滑鼠是圖中的黑點,則對應前event/gob會得到紅色的gob,且event/offset會得到黑點和紅色gob左上角的相對位置。對應後,event/gob會得到藍色的gob,且event/offset會得到黑點和藍色gob左上角的相對位置。

Bugfix: parse-url

REBOL 3.0目前剖析URL的時候有Bug,當Path出現「@」、「!」或中文、日文、韓文…的時候,Path的解析出錯。這是相當嚴重的問題,因為檔案名稱中很常出現各國語言,如果用URL表示檔案,就會出問題,例如「file:///C:/音樂/love.mp3」就無法被順利剖析。

剖析URL的函數是decode-url,事實上,此函數會去使用到system/intrinsic/parse-url物件的定義。在parse-url物件定義中,為了要讓path納入「@」與「!」,必須修改path-char的定義修改如下:

path-char: make bitset!
#{00000000EFFFFFF5FFFFFFF57FFFFFEA}

為了要納入各國語言(#"^(100)" - #"^(FFFF)"),更必須將它改成:

path-char: union
make bitset!
#{00000000EFFFFFF5FFFFFFF57FFFFFEA}
charset [#"^(100)" - #"^(FFFF)"]

我改天再把它呈遞給DevBase。

FORMAT與PRINTF的用法

REBOL 3.0提供format與printf函數,這兩個函數的參數完全一樣。Format函數會傳出格式化的字串,而printf則會印出格式化的字串。事實上,printf內部直接呼叫format。

>> source printf
printf: make function! [[
"Formatted print."
fmt "Format"
val "Value or block of values"
][
print format :fmt :val
]]
>>

下面是它們的使用範例:

>> format [ 20 #"/" -10 ] [ %my-rebol-file.r 31023 ]
== "my-rebol-file.r / 31023"

>> printf [ 20 #"/" -10 ] [ %my-rebol-file.r 31023 ]
my-rebol-file.r / 31023
>>

printf與format都需要兩個參數,第一個是格式規則,第二個是代換內容的區塊(block)。格式規則區塊內可以出現四種元素:
  • 正整數:指定內容長度,如果內容超過指定長度,則自動放寬。如果內容不滿指定長度,則「補上空白」,且內容「向左對齊」。
  • 負整數:指定內容長度,如果內容超過指定長度,則自動放寬。如果內容不滿指定長度,則「補上空白」,且內容「向右對齊」。
  • 字元:直接放置一個字元
  • 字串:直接放置此字串

使用format時,還可以透過/pad,指定補上某字元(或字串),而不是補上空白。例如:



>> format/pad [ 20 #"/" -10 ] [ %my-rebol-file.r 31023 ] #"."
== "my-rebol-file.r...../.....31023"

Format函數與寬字元

REBOL 3.0有提供一個函數名為format,用來進行輸出文字的格式化。許多函數都會用到format,例如what、ls。

format一遇到中文就會失靈,輸出格式亂掉,這是因為中文字是寬字元(Wide Character)。為了要修正format的此錯誤,我剛剛把Unicode Standard Annex #11 (East Asian Width) 所附的檔案整理過,找出其中屬於Full-Width與Wide的字元。接下來,就等我(或任何人)有空去修正format函數的定義了。
full-wide-width-charset: charset [
#"^(1100)" - #"^(1159)"
#"^(115F)"
#"^(2329)" - #"^(232A)"
#"^(2E80)" - #"^(2E99)"
#"^(2E9B)" - #"^(2EF3)"
#"^(2F00)" - #"^(2FD5)"
#"^(2FF0)" - #"^(2FFB)"
#"^(3000)" - #"^(303E)"
#"^(3041)" - #"^(3096)"
#"^(3099)" - #"^(30FF)"
#"^(3105)" - #"^(312D)"
#"^(3131)" - #"^(318E)"
#"^(3190)" - #"^(31B7)"
#"^(31C0)" - #"^(31E3)"
#"^(31F0)" - #"^(321E)"
#"^(3220)" - #"^(3243)"
#"^(3250)" - #"^(32FE)"
#"^(3300)" - #"^(33FF)"
#"^(3400)" - #"^(4DB5)"
#"^(4E00)" - #"^(9FC3)"
#"^(A000)" - #"^(A48C)"
#"^(A490)" - #"^(A4C6)"
#"^(AC00)" - #"^(D7A3)"
#"^(F900)" - #"^(FA2D)"
#"^(FA30)" - #"^(FA6A)"
#"^(FA70)" - #"^(FAD9)"
#"^(FE10)" - #"^(FE19)"
#"^(FE30)" - #"^(FE52)"
#"^(FE54)" - #"^(FE66)"
#"^(FE68)"
#"^(FF01)" - #"^(FF60)"
#"^(FFE0)" - #"^(FFE6)"
]

2008年5月28日

REBOL剖析URL時的問題

昨天用REBOL寫了一個Spider程式,要下載某些網站的內容。這些網站所使用到的URL中,有出現「!」與「@」等特殊字元,REBOL 2.x在剖析URL的時候,會因此判斷錯誤。因此。我必須自己剖析URL,然後利用下面的方式讀取資料:

read [
scheme: 'http
host: "www.some-host.net"
port-id: 80
path: "database/!data.html"
]

2008年5月20日

從OOP到FP

如果你只習慣OOP(Object-Oriented Programming)的編程方式,現在想改用FP(Functional Programming)的方式,但不知道要從何下手,你可以參考我的這篇文章。

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日

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月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很少有人用)。