visitor@wangyvdi.top:~$ cat posts/monkey/02_monkey_基本语法.md

Monkey 基本语法

#monkey #语法 #教程 2 min

交互式 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

在终端里读这篇:ssh -p 2022 wangyvdi.top cat posts/monkey/02_monkey_基本语法.md (原文 是同样的纯文本)