Lisp-family:对符号调用和符号的不同评估作为参数

时间:2015-12-15 09:28:40

标签: clojure scheme lisp racket s-expression

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

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

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

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

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

4 个答案:

答案 0 :(得分:5)

在Racket中,可以按照这种精神做一些事情:

  1. 您可以定义struct并为其指定prop:procedure。在应用程序中提供struct的实例时,将调用该过程。

  2. 您可以使用自己的函数覆盖默认的#%app,以便一般性地重新定义应用程序,并包括非struct的内容。例如,您可以执行诸如模拟Clojure的(key map)语法之类的操作,以便('symbol dict)实际上是(hash-ref dict 'symbol)

答案 1 :(得分:1)

作为lisp-1基本上意味着您不会以任何其他插槽的方式评估组合的第一个插槽。要为您编写的代码获取此类行为,您需要将其转换为根据lisp-1规则执行所需操作的代码。因此,您需要实现一个执行此转换的宏。

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

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

并将其评估为2。

答案 2 :(得分: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语法来实现。

答案 3 :(得分:1)

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]

使用特殊规则解决所有符号(abcg)的参数形式,该规则将函数和变量命名空间混合在一起。这是语言的核心。操作员可以直接访问环境,以实现这一目标。

特殊处理不会递归到(d e f),这是一种普通的Lisp-2形式。如果你想要语义,你必须把DWIM Brackets放在那里。

此外,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宏及其衍生自它的“堂兄弟”。

来自Rosetta Code的

Range Extraction任务:

(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)

接受的答案描述了用于将结构视为功能的球拍机制。 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)),当作为函数调用时,它会生成值101112,....可以为1以外的增量提供可选的delta参数:

(let ((acc (new (accum 0))))
  (list [acc 5] [acc 5] [acc])) -> (5 10 11)