1

lisp-family(编辑:lisp-1)语言中是否有一种方法可以区分符号评估作为函数或参数的位置(即在评估时覆盖该符号的评估)?
作为一个例子(我不需要这个功能,这是一个例子),我想对一组对象实现某种中缀操作,可以由对象本身调用

(my-obj some-operator arg1 ...)  

这实际上会将函数 some-operator 应用于 my-obj 和参数。
但是当此对象在代码中的其他任何地方用作参数时,例如:

(some-function my-obj &args...) 

它将评估为 my-obj 的值。
谢谢你。

4

4 回答 4

5

在 Racket 中,本着这种精神可以做几件事:

  1. 您可以定义 astruct并给它 a prop:procedure。当应用程序中提供了 的实例时struct,将调用该过程。

  2. 您可以使用自己的函数覆盖默认值#%app,以重新定义应用程序,并包括不是structs 的内容。例如,您可以模拟 Clojure 的(key map)语法,('symbol dict)实际上就是(hash-ref dict 'symbol).

于 2015-12-15T17:16:20.903 回答
1

作为一个 lisp-1 基本上意味着您不会以任何不同于任何其他插槽的方式评估组合的第一个插槽。无论如何,要使您编写的代码具有这种行为,您需要将其转换为在 lisp-1 规则下执行您想要的操作的代码。因此,您将需要实现一个执行此转换的宏。

例如,如果您想要中缀运算符,您需要编写一些宏infix,然后也许您可以编写:

(infix (+ - * /) (1 + 2 * 5 - 3) / 4)

并让它评估为2。

于 2015-12-15T13:47:42.937 回答
1

我一直在尝试在类似 OO CLOS 的方案中使用默认过程的想法。例如。那个写作

(obj 5 10)

如果 obj 是过程或方法,将验证 obj 并使用参数应用它,但如果不是,它将与默认调度程序相同,例如。

(default-dispatcher obj 5 10)

在这样的方案中,可以制作矢量访问器:

(define-method default-dispatcher 
  "Default dispatcher for vectors"
  ([obj %vector] [index %number])       -> (vector-ref obj index)
  ([obj %vector] [index %number] value) -> (vector-set! obj index value)
  (args ...)                            -> (error "No such method"))

; example usage
(define vec (vector 4 5 6 7))
[vec 1]     ; => 5
[vec 1 10] 
[vec 1]     ; => 10

在 Racket 中,这可以通过更改语言#%app语法来实现。

于 2015-12-15T17:04:00.613 回答
1

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。这是语言的核心。操作员可以直接访问环境以实现这一点。cg

特殊处理不会递归到(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)
于 2015-12-22T21:43:49.107 回答