2008年4月16日

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

沒有留言: