有趣的编程语言 Red
Red 项目最早始于 2011 年,项目由 Nenad Rakocevic 主导。Red 语言是一种同时具有函数式、声明式、符号式特性的现代编程语言,其目标是构建成一个全栈编程语言。Red 语言受到 Rebol 语言启发,两者语法高度相似。和 Rebol 语言只能解释执行不同,Red 语言还提供了 AOT 编译(生成独立的可执行文件)功能,在未来还将支持 JIT 编译。
Red 语言的主要特性:
- 多编程范式:命令式、函数式、符号式
- 基于原型的面向对象
- 跨平台
- 支持解释执行和静态编译
- 垃圾回收
- 面向底层系统编程的 Red/System 方言
- 内置 GUI 组件
- 元编程:code as data, homoiconicity
最神奇之处在于,这样一个全能的语言,它的编译器大小仅 1MB 多。
安装
在 Windows 上可以使用 Scoop 安装 Red 编译器:
powershellscoop install red-toolchain
scoop install red # 命令行控制台/解释器(可选)
scoop install red-view # GUI 控制台/解释器(可选)
以下是一个 Red 语言的 Hello World 示例:
redRed [title: "Hello World"]
print "Hello World!"
交叉编译
Red 语言工具链只需要简单的参数设置便可以实现交叉编译。目前支持的编译目标平台有:
MSDOS : Windows, x86, console (+ GUI) applications
Windows : Windows, x86, GUI applications
WindowsXP : Windows, x86, GUI applications, no touch API
Linux : GNU/Linux, x86, console (+ GUI) applications
Linux-GTK : GNU/Linux, x86, GUI only applications
Linux-musl : GNU/Linux, x86, musl libc
Linux-ARM : GNU/Linux, ARMv5, armel (soft-float)
RPi : GNU/Linux, ARMv7, armhf (hard-float)
RPi-GTK : GNU/Linux, ARMv7, armhf (hard-float), GUI only applications
Pico : GNU/Linux, ARMv7, armhf (hard-float), uClibc
Darwin : macOS Intel, console or GUI applications
macOS : macOS Intel, GUI-only, applications bundles
Syllable : Syllable OS, x86
FreeBSD : FreeBSD, x86
NetBSD : NetBSD, x86
Android : Android, ARMv5
Android-x86 : Android, x86
使用以下命令可以在 Windows 上分别交叉编译 Windows、Linux 和 macOS 的可执行文件:
powershellred-toolchain -t MSDOS hello.red # MSDOS 指 Windows 控制台程序
red-toolchain -t Linux hello.red
red-toolchain -t Darwin hello.red
目前,Red 只能编译生成 32 位程序,计划未来支持 64 位。
GUI 示例
Red 还自带一套简易的 GUI 组件,这使其拥有了跨平台 GUI 开发能力。
redRed [title: "GUI Example" needs: 'view]
view [
title "GUI Example"
below
input: field 400x30 "Input some text here"
across
button "Show" [
message: input/text
alert message
]
button "Exit" [unview]
]
Red 为 GUI 引擎设计了一套 DSL 方言和一个响应式框架。该 GUI 底层在 Windows 下使用原生 API,在 Linux 下使用 Gtk3,在 macOS 下使用 Cocoa。不过 UI 组件数量很少,没多少实用价值。
嵌入 Red/System
Red/System 是 Red 的底层开发方言,使用静态类型和手动内存管理,类似于 C 语言。可以在普通 Red 代码中嵌入 Red/System 代码进行混合编程。此外,Red 源代码也是通过转译成 Red/System 后进行编译的。
下面代码展示了在 Red 中调用本地 Windows API MessageBox()
弹出消息框:
redRed [title: "MessageBox Hello World"]
#system [
#import [ "user32.dll" stdcall [
message-box: "MessageBoxA" [
hWnd [integer!]
pText [c-string!]
pTitle [c-string!]
uFlag [integer!]
return: [integer!]
]
]]
]
show-msg: routine [
text [string!]
title [string!]
/local
c-text [c-string!]
c-title [c-string!]
][
c-text: as c-string! string/rs-head text
c-title: as c-string! string/rs-head title
message-box 0 c-text c-title 0
]
show-msg "World" "Hello"
Red 的文档几乎没有,示例代码十分有限,社区也几乎不存在。相关资源有限,因此别指望 AI 能写出正确的 Red 代码。上述代码是我根据 Red 编译器源代码写出来的,而 AI 写的代码没有一例可以通过编译。
Homoiconicity
Homoiconicity 一般翻译成同像性,也就是通常所说的代码即数据 (code as data)。简单地说,就是该语言的代码可以像数据一样进行操作,从而实现元编程。
Red 语言通过 Block 实现同像性。比如代码 block-example: [1 2 foo "foo" "bar" bar]
,其中方括号包起的部分就表示一个 Block,并将其赋值给 block-example
变量。Block 即可以用来表示列表,又可以用来表示字典,还可以用来表示代码。不同于 Lisp 系语言,Red 不需要显式声明 Block 的类型,编译器会根据上下文自动识别。
redblock-example: [3 2 1 foo "bar" name "Tony"]
; 将 block 当作列表访问
probe block-example/1 ; 3
probe block-example/5 ; "bar"
; 将 block 当作字典访问
probe block-example/foo ; "bar"
probe block-example/name ; "Tony"
; 删除 block 中倒数第二个元素 name
remove at block-example (length? block-example) - 1
probe block-example ; [3 2 1 foo "bar" "Tony"]
; 将 block 当作代码运行,block 的最后一个元素会作为返回值
foo: func [arg] [print ["The arg is:" arg]]
result: do block-example ; The arg is: bar
probe result ; "Tony"
其中,内置函数 probe
用于打印变量内容;内置函数 do
用于运行 Block 代码;斜杠 /
表示路径分隔,类似其他语言里的 .
或 ->
。
总结
Red 语言太小众了,社区孱弱,文档缺失。它目前远远未达到可用阶段,1.0 版本还遥遥无期。另外缺点也不少,比如错误信息可读性差,也缺乏调试工具。只能算是一个有趣的玩具吧。
Red 语言让人别扭的一点是,由于 Red 的标识符允许包含特殊字符 (+ - : ? & * _ ! ' < > | ~
等),因此标识符和运算符之间必须用空格分隔。比如 a-b
和 a - b
完全是两个意思:
reda: 2
b: 1
a-b: 999
probe a-b ; 999
probe a - b ; 1
另外 Red 也没有运算符优先级的概念。比如 x: 1 + 2 / 3 * 4
的值是 4,等价于 x: ((1 + 2) / 3) * 4
。