Monkey 基本语法
交互式 REPL 按行解析:下面的多行代码块适合保存成 .monkey 脚本;在 REPL 里要写成一行,或者把多条语句用 ; 串起来交给 monkey -e。仓库里的 demo.monkey 就是一个可以直接运行的脚本。
值
42
"hello"
true
false
[1, 2, 3]
{"name": "monkey", "year": 2026}
数组用下标取值,哈希用键取值:
[10, 20, 30][1]
{"name": "monkey"}["name"]
type_of 可以看类型:INT、STRING、BOOL、ARRAY、HASH、FUNCTION、NULL。
变量
let x = 10;
let name = "monkey";
x + 3
标识符只能由字母和下划线组成(addOne 可以,add1 不行)。变量用 let 绑定,没有 var / const。
运算
1 + 2 // 3
10 - 4 // 6
3 * 7 // 21
5 / 2 // 2,整数除法
1 < 2 // true
1 == 1 // true
1 != 2 // true
!true // false
只有 ==、!=、<、>;没有 <=、>=、&&、||。需要组合条件时用嵌套 if。
条件
if 是表达式,会返回值:
let max = fn(a, b) {
if (a > b) { a } else { b }
};
max(3, 8)
没有 else 时返回 null。if 的结果就是被选中的分支里最后一个表达式的值。
函数
let square = fn(x) { x * x };
square(7)
函数是值,可以返回函数,形成闭包:
let makeAdder = fn(n) {
fn(x) { x + n }
};
let addTen = makeAdder(10);
addTen(5)
递归直接引用函数名:
let factorial = fn(n) {
if (n == 0) { 1 } else { n * factorial(n - 1) }
};
factorial(5)
也可以显式 return:
let add = fn(a, b) { return a + b; 999 };
add(2, 3)
数组与内置函数
len("hello") // 5
len([1, 2, 3]) // 3
first([1, 2, 3]) // 1
last([1, 2, 3]) // 3
rest([1, 2, 3]) // [2, 3]
push([1, 2], 3) // [1, 2, 3]
这个解释器还预置了几个用 Monkey 自己写的函数:
map([1, 2, 3, 4], fn(x) { x * x })
reduce([1, 2, 3, 4], 0, fn(acc, x) { acc + x })
sum([1, 2, 3, 4])
fibonacci(10)
map:对数组每个元素调用函数,返回新数组。reduce:从初始值开始,把数组折叠成一个值。sum:reduce的简写。fibonacci:递归版斐波那契。
输出
puts 把参数打印出来,每个参数一行,返回 null:
puts("factorial(5) =", factorial(5))
factorial(5) =
120
null
最后那个 null 是 puts 的返回值,REPL 会把它也打印出来。
注释
// 这一行会被忽略
1 + 1
宏
宏在求值前展开,可以做语法层面的封装:
let unless = macro(cond, cons, alt) {
quote(if (!(unquote(cond))) { unquote(cons); } else { unquote(alt); });
};
unless(1 > 2, "no", "yes")
这个解释器已经预置了一个 unless,上面的定义只是演示宏的写法;重新定义会覆盖它。
一个完整例子
let square = fn(x) { x * x };
let factorial = fn(n) {
if (n == 0) { 1 } else { n * factorial(n - 1) }
};
puts(factorial(5));
puts(map([1, 2, 3, 4, 5], square));
puts(fibonacci(10));
sum([1, 2, 3, 4, 5]);
保存成文件后运行:
visitor@localhost:~$ monkey posts/monkey/demo.monkey