Clojure Lisp族:符号调用和符号作为参数的不同计算

Clojure Lisp族:符号调用和符号作为参数的不同计算,clojure,scheme,lisp,racket,s-expression,Clojure,Scheme,Lisp,Racket,S Expression,在lisp系列(编辑:lisp-1)语言中,是否有一种方法可以区分符号作为函数或参数的位置的求值(即在求值时覆盖此符号的求值)? 作为一个例子(我不需要这个功能,这是一个例子),我想在一组对象上实现某种中缀操作,对象本身可以调用它 (my-obj some-operator arg1 ...) 这实际上会将函数some运算符应用于我的obj和参数。 但当此对象在代码中的任何其他地方用作参数时,如: (some-function my-obj &args...) 它将评估为我的o

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

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

(some-function my-obj &args...) 
它将评估为我的obj值。

谢谢。

作为一个lisp-1,基本上意味着您对组合的第一个插槽的评估与其他插槽没有任何不同。要使您编写的代码具有这种行为,您需要将其转换为符合lisp-1规则的代码。因此,您需要实现一个执行此转换的宏

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

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

将其求值为2。

作为一个lisp-1,基本上意味着对组合的第一个插槽的求值与对其他插槽的求值没有任何不同。要使您编写的代码具有这种行为,您需要将其转换为符合lisp-1规则的代码。因此,您需要实现一个执行此转换的宏

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

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

并将其计算为2。

我一直在玩弄在类似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
语法来实现。

我一直在考虑在类似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
语法来实现这一点。

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

  • 您可以定义一个
    结构
    ,并给它一个。当应用程序中提供了
    struct
    的实例时,将调用该过程

  • 您可以使用自己的函数覆盖默认值,以重新定义应用程序,并包括不是
    struct
    s的内容。例如,您可以模拟Clojure的
    (键映射)
    语法,这样
    ('symbol dict)
    实际上就是
    (hash ref dict'symbol)


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

  • 您可以定义一个
    结构
    ,并给它一个。当应用程序中提供了
    struct
    的实例时,将调用该过程

  • 您可以使用自己的函数覆盖默认值,以重新定义应用程序,并包括不是
    struct
    s的内容。例如,您可以模拟Clojure的
    (键映射)
    语法,这样
    ('symbol dict)
    实际上就是
    (hash ref dict'symbol)

  • 在Lisp方言中,问题是从另一端解决的。从Lisp-2方言作为基础开始,我们是否可以利用Lisp-1方言的一些表现力优势,例如从大量使用高阶函数的程序中消除
    (function…
    #
    funcall
    噪音

    该设计以一个名为的特殊操作员为中心,该操作员代表“按我的意思做”或“以智能和有意义的方式进行调度”

    dwim
    操作符的调用使用方括号进行修饰,方括号被称为

    dwim
    操作符不仅仅是Lisp-2上的宏;它实际上更改了名称查找规则。当我们有

    (dwim a b c (d e f) g)
    
    或相当于:

    [a b c (d e f) g]
    
    所有符号化的参数形式(
    a
    b
    c
    g
    )都使用一个特殊规则进行解析,该规则将函数和变量名称空间合并在一起。这是语言的核心。操作员可以直接访问环境,从而实现这一点

    特殊处理不会在
    (def)
    中重现,这是一种普通的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
    宏及其派生的“近亲”

    来自Rosetta代码的任务:

    (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)])))) ","}`)
    
    此外,在TXR Lisp中可以调用各种有用的函数。例如,每个序列(列表、向量或字符串)都被视为将数字索引映射到元素的函数。因此,我们可以做到:

    (mapcar "abc" #(2 1 0))  -> #(#\c #\b #\a)
    
    公认的答案描述了将结构视为功能的球拍机制。TXR以
    lambda
    方法的形式提供此功能。这在与蓄能器Fac的连接中进行了说明