在TXR Lisp 方言中,问题是从另一端解决的。以 Lisp-2 方言为基础,我们能否利用 Lisp-1 方言的一些表现力优势,比如从大量使用高阶函数的程序中消除(function ...)
,#'
和噪音?funcall
该设计以一个名为 的特殊运算符为中心dwim
,它代表“Do What I mean”或“Dispatch,in a Way that is Intelligent and Meaningful”。
运算符的调用dwim
使用方括号进行修饰,称为“DWIM 括号”
dwim
运算符不仅仅是 Lisp-2 上的宏;它实际上改变了名称查找规则。当我们有
(dwim a b c (d e f) g)
或等效地:
[a b c (d e f) g]
所有符号形式的参数形式(a
、和)都使用一个特殊的规则来解析,该规则将函数和变量命名空间混合在一起b
。这是语言的核心。操作员可以直接访问环境以实现这一点。c
g
特殊处理不会递归到(d e f)
,这是一个普通的 Lisp-2 形式。如果你想要语义,你必须把 DWIM 括号放在上面。
此外,dwim
操作符通过宏扩展得到了适当的处理。例如,给定:
(symacrolet ((localfun whatever))
(flet ((localfun () ...)))
[a b c localfun] ;; refers to the flet as a function object!
(a b c localfun))) ;; refers to the symbol macro!
宏扩展器知道dwim
及其语义,因此它考虑localfun
引用函数和变量名称空间的可能性。任一命名空间中最接近的词法绑定是 the flet
,因此符号宏扩展被抑制(隐藏)。
语义隐含在dwim
部分评估op
宏及其派生的“表亲”中。
Rosetta Code 中的范围提取任务:
(defun range-extract (numbers)
`@{(mapcar [iff [callf > length (ret 2)]
(ret `@[@1 0]-@[@1 -1]`)
(ret `@{@1 ","}`)]
(mapcar (op mapcar car)
(split [window-map 1 :reflect
(op list @2 (- @2 @1))
(sort (uniq numbers))]
(op where [chain second (op < 1)])))) ","}`)
Y 组合器:
;; The Y combinator:
(defun y (f)
[(op @1 @1)
(op f (op [@@1 @@1]))])
;; The Y-combinator-based factorial:
(defun fac (f)
(do if (zerop @1)
1
(* @1 [f (- @1 1)])))
;; Test:
(format t "~s\n" [[y fac] 4])
此外,在 TXR Lisp 中,各种有用的东西都是函数可调用的。例如,每个序列(列表、向量或字符串)都被视为将数字索引映射到元素的函数。因此我们可以这样做:
(mapcar "abc" #(2 1 0)) -> #(#\c #\b #\a)
接受的答案描述了一种将结构视为功能的球拍机制。TXR 以方法的形式具有此功能lambda
。这在 Rosetta 中累加器工厂任务的“基于 OOP”的解决方案中得到了证明:
(defstruct (accum count) nil
(count 0))
(defmeth accum lambda (self : (delta 1))
(inc self.count delta))
我们可以实例化 a (new (accum 9))
,它在作为函数调用时会产生值10
, 11
, 12
, ...。可以为除 之外的增量提供可选的 delta 参数1
:
(let ((acc (new (accum 0))))
(list [acc 5] [acc 5] [acc])) -> (5 10 11)