歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux編程 >> Linux編程 >> Red語言:向編程復雜性反擊

Red語言:向編程復雜性反擊

日期:2017/3/1 9:28:27   编辑:Linux編程

你是否曾對軟件編程棧的混亂感到過困惑?錯綜復雜和臃腫的解決方案無處不在,但無論是在當代軟件的構建還是維護環節,很少有架構師和程序員能真正意識到由此帶來的成本。Red的存在正是為了反擊這種復雜性,這是它最主要的設計目的。沒錯,在現代軟件世界中,“簡單”的工具和簡單的解決方案仍是可以企及的。這是個所有人都竭力掖藏的行業秘密(這可不是什麼好事兒),但自1997年以來,解決方案其實已由Rebol編程語言給出。Red繼承自Rebol譜系,並嘗試將Rebol原先的使用范圍加以大大拓展。Red是個雄心壯志的項目,它想要成為首個全棧編程語言。以下是其主要特性和設計目標:

  • 范式無關,默認提供函數式/命令式/符號式范式
  • 支持基於原型的對象
  • 同像語言(Red語言是其自身的元語言)
  • 既能以靜態方式,也能以JIT方式編譯為本地代碼
  • 強力支持並發和並行(通過Actor和並行聚集)
  • 通過內置Red/System DSL提供底層系統編程能力
  • 提供高級腳本特性和REPL控制台支持
  • 高度可嵌入(​​像Lua一樣,或者更好一些)
  • 低內存占用,支持垃圾回收
  • 低磁盤空間占用(<1MB)
  • 生成單個的命令行可執行文件
  • 零安裝、零配置
  • 獨立的跨平台工具鏈
  • 除運行的操作系統外,概無其他依賴

Red語言,正如Rebol一樣,依靠獨特的途徑來編程,與目前主流語言的主張有所不同。以下是JSON發明者Douglas Crockford對Rebol語言發表的評論:

Rebol是一種更具現代性的語言,但也有些與Lisp語言非常相似的思想蘊涵在內,主要體現在它也是完全建立在先進行數據表示、爾後將其作為程序執行起來這樣的基礎之上。但它擁有更豐富的語法材料。Rebol是一種才華橫溢的語言,它本該更普及一些,現在卻並未如此,這可引為憾事。

Red和Rebol的設計目標是要盡可能地提供表達能力,同時保持源代碼的高可讀性,事實上它們的源代碼很接近自然語言。2013年的一項將程序設計語言按表達能力排序的研究項目中,Rebol語言名列第三,僅次於Augeas和Puppet這兩種DSL(http://goo.gl/qyPXx)。這有力地表明,在所有通用型程序設計語言中,Rebol是表達能力最強的一個。Red和Rebol都遵守務實設計原則,沒有哪部分是拍腦袋的決定,或是“為了不同而不同”。每個語法或語義背後,都有明確的設計理由。

Red語言初探

Red和Rebol如何在企及如此水平的效率的同時,又保持“簡單”呢?根本的原因之一,是因為這兩者都既是一種數據格式,又是一門程序設計語言。此特性繼承自Lisp,特別是s-表達式概念。Lisp中也建立了Red和Rebol所依賴的元編程模型。它們都是同像語言,所有的代碼都表示為數據。值存儲在塊中(使用方括號記法:[……]),即普通列表,這和Lisp的記法一樣,但它們不要求函數調用的那對括號,這就使得代碼看上去更像自然語言。函數在默認情況下采用前綴記法,然而,Red和Rebol也支持針對數學和布爾運算符采用中綴表示法,這為代碼閱讀提供了便利。采用這種純元編程進行程序設計,反射、熱補丁、甚至即時編碼這些語言特性都能得到內建支持,不需要學習任何新API,也無須特別的庫支持,只使用基本函數進行數據操作即可。以下是使用Red語言REPL的示例:

$ red
red>> code: ["hello"]
== ["hello"]

red>> insert code 'print
== ["hello"]

red>> code
== [print "hello"]

red>> do code
hello

red>> code/2: 123
== 123

red>> code
== [print 123]

red>> append code [+ 1]
== [print 123 + 1]

red>> do code
124

red>> length? code
== 4

red>> type? code/1
== word!

red>> foreach value code [probe type? value]
word!
integer!
word!
integer!

如君所見,該語言的基本構件如下:

  1. 值:它們代表著數字、時間、字符串、文件名和URL等,如123 45.6 10:20:30.456 192.168.1.0 "Hello" http://red-lang.org。
  2. 字:它們可以被用作“變量”(但不是所有的都可以),如print block? string! map-each ?? + =。
  3. 塊:由值、字和塊以任何順序組合而成,如[1 2 3] [123 "abc" print 10:20]。

這些就是用來表示數據、構建表達式、定義函數、創建對象、以及構造更復雜數據類型的基本構件。符號都是一等(first-class)值,也是一種更自然也更有效的字符串替代品,這對於很多用例都適用,尤其是涉及查找操作時就更能說明問題,因為符號可以以O(1)的效率比較,而字符串則要求O(n)。符號不區分大小寫,所以print、Print和PRINT是等同的,人類語言不也是這樣嗎?

Rebol或Red程序源代碼通常都是UTF-8輸入字符串,它們都會被LOAD化處理。LOAD是原生的核心功能,能夠將任何字符串變換成包含在一個塊中的內存二進制格式。塊將值存儲至128比特的相鄰單元內。值主要分為標量值(其尺寸固定)或序列值(用戶可以向其中添加/刪除數據)。數字、日期、元組和值對是標量值的,而值塊、字符串、URL、路徑、文件和標簽是序列值的示例。標量值通常可以置入單個存儲單元,而序列值則需要額外內存。

因此,塊是帶有垃圾回收的內存管理器進行保留和回收的主要分配單位。Rebol采用經典的stop-the-world標記和清理垃圾回收算法,而Red則依賴於stop-the-thread分代壓縮垃圾回收算法(尚未完全實現),交替進行部分或全部遍掃。Red將擴充其垃圾回收算法,在未來實現增量回收,以使得它可以用來開發實時應用,例如60-FPS的街機游戲。

一旦源代碼被加載入內存,變成一個值塊,它就只是純粹的數據。默認地,在遍掃源代碼,使之變換成Red或Rebol二進制文件時,就會對值進行計算。如果是用Rebol語言,加載的塊會被解釋執行;如果是用Red語言,它們就將被編譯成本地代碼,但目的都是為了完成計算。然而,值塊以何種方式進行解釋,則是依賴於語境的。解釋方式有如下幾種:

  1. 函數式:由某個函數來取參計算
  2. 作為一種特殊語法:即所謂方言(指DSL)
  3. 通過Parse方言語句:匹配(matching)、回溯(backtrack),以及生成(production)
  4. ad-hoc代碼:你想如何處理,由自己決定

默認的(非純的)、以函數式方式解釋的語言(即我們通常所謂的“代碼”),是一種面向表達式的語言,它帶有很簡單的語義規則:

  1. 沒有關鍵字
  2. 帶有稱為“改進”的可選擴充的定參函數
  3. 單一或多值的函數參數和返回值
  4. 表達式由左到右求值
  5. 中綴運算符優先級高於前綴函數調用

因此,浮在語言上方的函數層可以很容易地被任何自定義計算體取代(例如,撰寫一個類似於Prolog的解釋器將非常簡單)。這使得Red和Rebol具備了極好的可延展性,十分容易適應任何你可能的需要。這種靈活性是DSL得以成為一種自然的方式解決一些計算任務,通過提供特定領域的微語言對於給定的任務實現優化的基礎。Red和Rebol憑借這種力量,在核心語言和標准庫中廣泛地使用了嵌入式DSL:

  1. VID:視圖接口方言(View Interface Dialect)是用於建立GUI的DSL
  2. Draw:進行2D繪圖的DSL
  3. Parse DSL:一種類BNF語法解析DSL
  4. Security Dialect:一種在運行時用於控制安全沙箱特性的DSL
  5. 函數規格:函數原型亦使用DSL來描述

使得嵌入式DSL的創建容易、便捷的因素有:

  1. Parse DSL:一種強大的TDPL,並帶遞歸和回溯支持
  2. 可將Red或Rebol代碼直接內嵌於規則解析的能力
  3. 豐富的數據類型:已支持數十種常用數據的字面量符號,所以沒有必要建立特殊規則來解析之

下面是一些在Rebol2中的GUI DSL的示例:

按一個大小為100×100的紅色按鈕,以打開一個窗口:

>> view layout [button "Hello" red 100x100]

顯示會觸發一個動作的按鈕:

>> view layout [button "Hi" [print "Hello!"]]

顯示按鈕,打印一個字段的內容:

>> view layout [
in: field 200
button "Print" [print in/text]
]

Red語言中的一個Parse DSL示例:

  red>> digit: charset "0123456789"
  red>> parse "hello 888 world" [
  some [copy n some digit | skip]
  ]
  red>> n
  == "888"

與Rebol相比,Red帶來了什麼?

由於想要解決Rebol語言的一些不足之處,Red語言應運而生。這些不足包括:

  1. 性能不夠高(接近Ruby/ PHP)
  2. 缺乏底層編程能力
  3. 不能利用多核,並發支持有限
  4. 缺少對移動操作系統的支持(在2013年才對Android提供有限的支持)
  5. 不開源(開源時限僅至2012年12月,且僅限於Rebol第3版)

Red在解決以上大部分問題時都采用了創新設計:嵌入一個低層次的程序設計語言,它可以直接編譯為本地代碼,即Red/System。它采用Red語法(值仍為塊的形式),但與C類似,語義級別更低。它是靜態類型語言,並僅提供少數幾種數據類型:integer!、float!、float32!、byte!、logic!、pointer!、struct!,以及function!。它算支持指針算術,這賦予了它近於C的力量。標准庫也非常簡約,所以純Red/System編譯後的代碼尺寸非常小,下面這個程序:

Red/System [
	Title: "Hello World app"
]
print "Hello World!"

編譯後通常小於10KB。

Red程序被編譯成Red/System代碼,並與Red標准庫鏈接,而Red標准庫則大部分采用Red/System,少部分用Red自身寫就。該庫目前未壓縮體積約為200KB。我們的目標是在發行1.0版時,將其控制在500KB左右。

Red與Red/System緊密集成,有數種方法在Red語言中調用或內嵌Red/System代碼。其中最有用的一種是“常規”函數類型,它允許定義一個Red函數,其函數體為純Red/System代碼。Red語言會為你自動完成傳遞參數和返回值的裝箱/拆箱操作。有了Red/System的幫助,Red語言便可以解決從硬件到DSL的任何抽象層次,從而成為真正的首個全棧編程語言。

因此,Red依靠Red/System工具鏈來生成可執行文件。該編譯器和鏈接器目前支持的目標平台包括:

  1. CPU:IA-32、ARMv5和有限的AVR-8支持(Atmel328P)
  2. 文件格式:PE、ELF、Mach-o、.dll、so、APK,以及Windows驅動程序
  3. 計劃支持的其他格式:
  4. 後端:IA-64、ARMv7、asm.js、JVM、CLR、Dalvik,以及LLVM
  5. 文件格式:.lib、.a、.ipa,各種驅動程序格式,war(Web歸檔)

除此之外,Red語言還依靠橋接技術,以訪問像Java那樣的虛擬機,尤其是提供對Android的支持。事實是,目前已可通過Red/Java橋,采用JNI技術來從Red程序遠程控制Java和Android API,並獲取事件返回。2014年晚些時候,我們還計劃推出Red/Obj-C橋,以訪問iOS和Cocoa API。

盡管後端和文件格式的組合可能性繁多,但確定選用何種目標平台的Red配置文件卻短小精悍。這就使得交叉編譯變得非常簡單,例如:

從Linux或Mac平台上生成一個Windows平台的可執行文件:

$ red -t Windows hello.red

從Windows平台上生成一個Raspberry Pi平台的可執行文件:

$ red -t Linux-ARM hello.red

以下是關於這些目標平台的定義:

Windows [
	OS:	'Windows
	format: 	'PE
	target:	'IA-32
	type:	'exe
	sub-system: 'GUI
	]

Linux-ARM [
	OS:	'Linux
	format:	'ELF
	target:	'ARM
	type:	'exe
	base-address: 32768	; 8000h
	dynamic-linker: "/lib/ld-linux.so.3"
	]

Red語言的開發工作仍然任重道遠。目前它的工具鏈部分使用Rebol2完成自舉(指Red語言和Red/System編譯器+鏈接器)。由於需支持JIT編譯動態生成的Red/System代碼,Red語言必須有自承載能力,所以所有工具鏈需要在1.0版之後用Red語言重寫。新的工具鏈將能生成真正包含全部特征的Red語言,並同時為兩種編譯器提供優化層,生成更小更快的代碼。目前,Red/System的性能實測下來大約比C慢4~6倍,這對於未經優化的本地代碼而言已經不錯了。

性能還會隨著即將到來的並發支持而得到提升。今年晚些時候,Red語言會提供一個完全異步I/O接口,以及M:N線程模型(M個輕量級線程,分發到N個OS線程中去)。根據目前的計劃,更高級別的抽象會使用Actor模型,這是為了實現簡單而高效的共享狀態同步。從用戶的角度看,Actor也只是個一等的數據類型,和使用任何其他對象都差不多,很少或者根本沒有額外的語法負擔。然而,考慮到Go語言的goroutine模型的擁趸之多,我們仍在斟酌各種選項以決定使用Red語言的最佳模式。

Red語言是一個開源項目,采用BSD許可證。作為語言的作者,我全職工作於此業已三年。項目資金來自用戶和支持者捐款。自2011年首次發布以來,得到的支持已然令我難以置信。開發者對於Red語言可提供的一切感到驚喜,尤其是那些了解Rebol語言能力的用戶。Red語言對於他們中的大多數人,包括我自己,都是夢寐以求的工具。Red語言再次將樂趣帶回了程序設計,將復雜性拒之門外,讓程序員們再次感覺控制在握,就像那曾經經歷的8位機時代。

從中國開始

由於Red語言將具備強大的Andr​​oid支持,又格外適合新入行的程序員,我們希望它能夠被世界上最大的Andr​​oid市場——中國所接受。在中國,程序員數量巨大,而最有才華的Red語言貢獻者中,就有一位是來中國上海的程序員謝晴天。

你可以從http://www.red-lang.org/p/download.html下載Red二進制文件。可執行文件只有半兆字節,包含了整個工具鏈,其中包括Red語言和Red/System編譯器,一個帶有可選控制台的解釋器,還有目前支持30余種數據類型的整個標准庫。你也可以嘗試雖然老舊一些,但比較完整的Rebol2解釋器,尤其是在測試GUI DSL時。

Copyright © Linux教程網 All Rights Reserved