【问题标题】:Why do some lisps put the function name outside of the argument list in a function definition?为什么有些 lisps 将函数名放在函数定义中的参数列表之外?
【发布时间】:2017-06-06 01:52:30
【问题描述】:

常见的 lisp 和 clojure 做

(defn function-name (arg1 arg2) (body))

球拍/计划确实

(defn (function-name arg1 arg2) (body))

后者对我来说更有意义,因为函数定义和调用的语法是相似的。前者的原因是什么?

【问题讨论】:

  • 我认为真正的答案是“历史”:Scheme 及其变体做出了一种选择,MACLISP 及其后代做出了另一种选择。我相当确定其他没有活后代的早期 Lisps 还有其他语法:我忘记了 InterLisp 做了什么,但它可能是一些奇怪和不同的东西。

标签: clojure scheme lisp common-lisp racket


【解决方案1】:

TL;DR 这并不像你说的那么简单。语法略有不同,每次有人创建一种语言时,他们都会决定新的语法,通常是为了使以前的语言或语言具有需要它的设计更简洁。当然,什么是“更好”是见仁见智的问题。

在Scheme(和后代Racket)中,变量和函数都有一个命名空间。因此,您对所有内容都使用define

(define variable 10)
(define function (lambda (arg1 arg2) body ...))

现在define 有最后一条捷径,即:

(define (function arg1 arg2) body ...)

所以规则是,如果第一部分是pair?,则应该使用lambda 将其扩展为更长的形式。我猜它类似于应用程序只是一个巧合。这个额外的功能只是为了节省一些击键,并且在像 The little Schemer 这样的书籍中经常被省略,因为它有两种方式和学习者,他们可能认为定义一个函数的绑定比定义 10 更特别,这是荒谬的。其余的论点通常令人困惑。例如。这些都是一样的:

(define (test . x) x)
(define test (lambda x x))

在 Common Lisp 中,您有两个命名空间,因此 defun 仅用于全局范围,并且存在生成函数的变量形式的函数等价物。在defun 中,您在 Common Lisp 中也有一个列表第一个参数,但它的作用完全不同:

(defun (setf name) (new-value)
  body ...)

这提供了一种获得与 CL 中其他访问器相同的对称性的方法。例如。如果(car x) 从一个缺点(setf (car x) 10) 中获取汽车价值,则会改变它。在我的示例中,name 的使用方式与car 相同。这很方便。

Clojure 使用 deffn 来实现,并使用数组作为参数:

(def function (fn [arg1 agr2] body ...))

defn 只是一个简写版本,就像以一对开头的 define 一样。它最终没有与 Scheme 更相似的原因可能是参数数据是一个数组这一事实,或者它们使语法尽可能接近原始。如果我没记错的话,您可以将函数名称作为 fn 的第二个参数,同时使 fndefn 看起来几乎相同。

【讨论】:

    【解决方案2】:

    后者对我来说更有意义,因为函数定义和调用的语法相似。

    在 Common Lisp 中,函数定义通常与调用不相似,因此假装它们是没有意义的。

    这是一个有效的函数定义:

    (defun foo (arg1 arg2
                &optional (ovar 10)
                &rest args
                &key (ak 11 a-p)
                &allow-other-keys
                &aux (aux1 12))
      (list arg1 arg2 ovar args ak a-p aux1))
    

    这些是上述的有效调用:

    (foo 1 2)
    (foo 1 2 3)
    (foo 1 2 3 :ak 4)
    (foo 1 2 3 :foo 10 :ak 4)
    

    因此调用参数看起来与定义参数列表不同。

    DEFMETHOD 的情况下,定义可能如下所示:

    (defmethod (setf foobar) :around ((value integer) (object foo))
      (setf (slot-value object 'a) value))
    

    电话会是

    (setf (foobar object) 10)
    

    总结

    在 Common Lisp 中,函数定义看起来并不像调用

    游览

    为简单的 CL 函数定义类似于 Scheme 的语法很简单:

    (defmacro define ((name &rest args) &body body)
      `(defun ,name ,args ,@body))
    
    CL-USER 36 > (macroexpand-1 `(define (foo a b c) (baz) (bar)))
    (DEFUN FOO (A B C) (BAZ) (BAR))
    T
    

    有些程序甚至使用类似的东西...

    【讨论】:

      【解决方案3】:

      函数定义只是 Lisp 家族中的一个操作。让函数定义类似于函数应用,其实意义不大。

      【讨论】:

        猜你喜欢
        • 2013-08-25
        • 1970-01-01
        • 2017-07-07
        • 1970-01-01
        • 1970-01-01
        • 2018-10-23
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多