在TXR Lisp 方言中,问题是从另一端解决的。以 Lisp-2 方言为基础,我们是否可以为自己披上 Lisp-1 方言的一些表现力优势,比如从大量使用更高级别的程序中消除(function ...)、#' 和funcall 噪音?排序函数?
设计以一个名为dwim 的特殊运算符为中心,它代表“按我的意思做”或“以一种智能且有意义的方式调度”。
dwim 运算符的调用使用方括号进行修饰,称为"DWIM Brackets"
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 引用函数和变量命名空间的可能性。任一命名空间中最接近的词法绑定是flet,因此符号宏扩展被抑制(隐藏)。
dwim 语义隐式用于部分评估 op 宏及其派生的“表亲”。
Range Extraction 来自 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 Combinator:
;; 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)
接受的答案描述了一种将结构视为函数的 Racket 机制。 TXR 以lambda 方法的形式提供此功能。这在 Rosetta 中的累加器工厂任务的 "OOP-Based" solution 中得到了演示:
(defstruct (accum count) nil
(count 0))
(defmeth accum lambda (self : (delta 1))
(inc self.count delta))
我们可以实例化一个(new (accum 9)),它会在作为函数调用时产生值10、11、12、...。可以为 1 以外的增量提供可选的 delta 参数:
(let ((acc (new (accum 0))))
(list [acc 5] [acc 5] [acc])) -> (5 10 11)