函数与控制流
(defn greet (name) (echo hello $name))
(if (test -d src) (greet developer) (echo missing))
(if (eq $EDITOR vim) (echo using vim))
(if (not (test -f config.txt)) (echo configuration missing))
(do (let message "multiple expressions") (echo $message))if 只对选中的分支求值。条件必须产生布尔值(来自 eq、数值比较或 not)或命令退出状态;
退出状态为零表示真。文本和数值不会隐式转换为布尔值。每个括号表达式都会创建新的词法作用域,
因此分支中的 let 不会泄漏到 if 外部。
do 创建一个作用域,并在其中依次执行表达式;直接写在其体内的 let 绑定留在这个作用域中。
for 先在循环外求值列表,再为每次迭代创建新的词法作用域和循环绑定。
while 在每轮开始前检查条件。两种循环都接受一个或多个循环体表达式,并在每轮创建
独立作用域:let 的绑定留在本轮中,set 可以更新外层绑定。
and/or 从左到右短路,统一返回布尔值;(and) 为真,(or) 为假。
它们沿用 if 的条件规则,可直接检查命令状态。
(let count #0)(while (< $count #5) (set count (+ $count #1)) (if (= $count #2) (continue)) (if (= $count #4) (break (list stopped $count))) (echo iteration $count))(continue) 跳过本轮剩余表达式。(break) 结束最近一层循环;(break 值) 对值求值一次,
并将其作为循环返回值,支持数值、列表、映射、布尔值和 nil。没有显式指定退出值时,循环返回
最近一次完整迭代的结果;没有完整迭代则返回 nil。被跳过或提前结束的迭代不会覆盖此前结果。
上述示例输出 iteration 1 和 iteration 3,并返回 ("stopped" #4)。
循环跳转不能跨越函数边界。在当前函数没有活动循环体时使用会报错。循环条件或列表表达式
在自身循环体之外执行,其中的跳转只作用于已有的外层循环。while 循环体中的命令失败
会立即停止执行,即使整个循环被用作条件也是如此。
函数名和参数声明使用裸名字;读取参数和局部变量的值时使用 $name。
每次函数调用创建新的调用作用域;函数体中的 let 绑定留在该作用域中,
同一作用域重复 let 会报错。函数捕获定义时的词法作用域,并返回最后一个表达式的值。
参数表达式在绑定形参之前求值。函数既可以返回命令输出,也可以返回数值、列表、映射和布尔值。
函数用作值时,会捕获整个函数体的标准输出:如果最后一个表达式产生命令退出状态,
则返回捕获的输出文本;否则直接返回最后一个表达式的值,此前捕获的输出不再显示。
函数值与参数
Section titled “函数值与参数”fn 创建匿名函数,function 显式取得命名函数或普通内置函数的值。
函数值可以保存在集合中、传参或返回,并支持表达式作为调用头:
(let inc (fn (x) (+ $x #1)))($inc #2)((fn (x) (* $x #2)) #3)(let add (function +))(apply $add #1 [#2 #3])
(defn sum (first &optional (second #0) &rest more) (let result (+ $first $second)) (for n $more (set result (+ $result $n))) (return $result))(sum #1 #2 #3 #4)参数顺序为必选参数、&optional、&rest name。可选参数可以只写名字,缺省为 nil;
(name default) 的默认表达式仅在缺参时、每次调用中求值,可以访问前面的参数和捕获环境。
可选参数按位置依次消费实参,剩余实参组成 rest 列表;列表实参保持为一个完整值。
apply 将最后一个列表展开为实参,并允许在列表前提供固定实参,所有值都不会再次解析或求值。
普通数据继续采用值语义;复制函数值保留相同的函数身份和捕获环境。
eq 按函数身份比较;函数引用保留取得时的定义,后续重定义不会改变已有引用。
闭包读取定义处的词法作用域,外层 set 的更新仍可见。函数值显示为 <function name>,
不能隐式转为文本、外部命令参数或环境变量。
function 不接受宏、外部命令或 if、and、let 等特殊形式。
get、not、数值与集合操作,以及 glob、cd、type 等普通内置支持函数引用。
(return) 提前返回 nil,(return expr) 求值一次并退出当前函数;可以穿过循环、
嵌套表达式和重定向,不会退出调用方函数。在函数外使用会报错。
命令表达式作为返回值时沿用普通值位置的输出捕获规则。
宏体也可用 return 提前返回表单;宏展开代码中的 return 则作用于调用方函数。
(defn greet (who) (str "hello, " $who))(greet parsh)(if #true (list yes) (list no))(for item (list first last) (str $item))交互环境依次显示 "hello, parsh"、("yes") 和 "last"。循环返回最后一次循环体的结果,不会收集每次迭代的值。这组示例可以直接在浏览器终端中运行。
apply 也接受 command 创建的外部引用和普通文本名称,包括 "str/join" 这样的引号名称。
异常处理使用 try/catch/finally 和 throw,见执行结果与后台任务。