【问题标题】:What is the nature of designators?代号的本质是什么?
【发布时间】:2015-02-10 05:40:25
【问题描述】:

Svante 通过在另一个答案中显示字符串指示符让我大吃一惊:

(string= :& "&") -> T

看看 CLHS,他们说A designator is an object that denotes another object. 这很好,但由于这些是不同的对象,某种强制需要在某处发生。我的意思是,如果“非零原子”可以满足以下列表指示符,则在某处存在一些逻辑来处理此问题。

列表指示符 n。对象列表的指示符;也就是说,一个 表示一个列表的对象,它是以下之一:非零原子 (表示一个单例列表,其元素是那个非零原子)或 正确的列表(表示它自己)。

我认为指示符可能只是一个概念,例如,泛型函数......但是来自 CLHS 的以下行......

除非另有说明,在表示对象的情况下 可能会被多次使用,这取决于实现是否 对象仅被强制一次或强制是否每次都发生 对象必须使用的时间。

... 看起来非常具体。

所以我的问题

  • 什么是指示符如何在实现中实现的示例?
  • 用户是否可以以任何方式扩展此机制?
  • 这种机制在指示符之间是否一致? (在 clhs 中似乎有 18 种指示符)

干杯

【问题讨论】:

    标签: common-lisp


    【解决方案1】:

    指示符只不过是指定另一个对象的对象。他们的语言没有什么特别之处。指示符的概念只是使某些编程实践更容易的概念。词汇表说:

    designatorn。表示另一个对象的对象。在里面 如果参数被描述为一个运算符的字典条目 类型的指示符,操作符的描述写在 假设对该类型的适当强制已经 发生了;也就是说,参数已经是指定的类型。 更多详细信息,请参阅Section 1.4.1.5 (Designators)

    该部分的链接很有帮助:

    1.4.1.5 Designators

    指示符是表示另一个对象的对象。

    如果运算符的参数被描述为指示符,则 操作员的描述是以一种假设的方式编写的 参数的值是表示的对象;也就是说, 参数已经是指定的类型。 (具体的性质 由“«类型»指示符”或“用于 «type»”可以在“«type»指示符的词汇表条目中找到。”)

    能够在词汇表中查找内容会有所帮助。例如,字符串指示符是可以代表字符串的东西:

    string designatorn。字符串的指示符;也就是说,一个 表示字符串的对象,它是以下之一:一个字符(表示 以字符为唯一元素的单例字符串), 符号(表示作为其名称的字符串)或字符串(表示 本身)。意图是该术语与行为一致 字符串;扩展字符串的实现必须扩展含义 以兼容的方式使用该术语。

    标准也恰好定义了函数string,它获取由字符串指示符指定的字符串:

    返回一个由 x 描述的字符串;具体来说:

    • 如果 x 是字符串,则返回它。
    • 如果 x 是符号,则返回其名称。
    • 如果 x 是一个字符,则返回一个包含该字符的字符串。 string 可能会执行额外的,实现定义的 转化。

    这简化了必须处理字符串和类似字符串的函数的实现。例如,您可以定义一个 ma​​ke-person 函数接受一个字符串指示符:

    (defun make-person (name)
      "Return a person with the name designated by NAME."
      (list :name (string name)))
    
    (defun person-name (person)
      "Return the name of a person (a string)."
      (getf person :name))
    

    指示符的概念只不过是一种编程约定,它使定义灵活的 API 变得更加容易。 Common Lisp 被定义为一种将现有 Lisp 联合起来的语言,它可能是统一不同实现行为的更简单方法之一。

    case 中使用了列表指示符的概念

    list designatorn。对象列表的指示符;那是, 一个表示列表的对象,它是以下之一:非零原子 (表示一个单例列表,其元素是那个非零原子)或 正确的列表(表示它自己)。

    case keyform {normal-clause}* [otherwise-clause] => result*

    normal-clause::= (keys form*)

    keys——对象列表的指示符。情况下, 符号 t 和其他符号不得用作键指示符。到 将这些符号本身称为键、代号 (t) 和 (否则)必须分别使用。

    我不知道返回由列表指示符指定的列表的函数,但它很容易编写(这不处理 t 的特殊行为,否则 case 需要,但它通常处理列表指示符):

    (defun to-list (x)
      "Return the list designated by x."
      (if (listp x) x
        (list x)))
    

    此类约定有时在您自己的代码中很有用,尤其是在您定义事物时存在事物的“注册表”时。例如,如果您写过以下任何一种:

    (defmacro deftransform (name &rest args)
      `(setf (gethash ',name *transforms*)
             (make-transform ,@args)))
    

    (defmacro deftransform (name &rest args)
      (setf (get ',name 'transform) (make-transform ,@args)))
    

    然后您可以将变换指示符的概念定义为变换对象或符号(它指定 *transforms* 表中符号的值,或符号上变换属性的值)。例如:

    (defun transform (x)
      (if (transformp x) x
        (gethash name *transforms*)))
    

    (defun transform (x)
      (if (transformp x) x
        (get x 'transform)))
    

    这可能会使您的部分代码更易于使用。函数指示符类似

    【讨论】:

    • 哇,太棒了,这两个答案都让我现在理解这一点。非常感谢历史的细节和总体完整性。谢谢大家!
    • @Baggers 是的,一旦你理解了这个想法,它既令人印象深刻又令人印象深刻。如果你很好地使用了指示符,你的 API 感觉很好用,这很好,但它也是一个非常简单的概念,所以你会发现自己在问‘这是否如此重要以至于我们实际上需要一个名字? (我发现自己说,当我终于读到“基于构造函数的依赖注入”时;我说“哦,就这些吗?”)
    【解决方案2】:

    什么

    对象的指示符是不一定是对象的东西,但可以从中推断对象。任何对象都可以简单地指定自己。

    例如,character不是string(a 的子类型),但character有时可以用来代替string因为它表示一个单字符的字符串。

    如何:系统级

    实现方式不同,请查看它们各自的源代码。 您可以在下面找到类似使用级别的代码或类似的内容

    (defun human-address (human)
      (etypecase human
        (human ...)
        (string (human-address (gethash human *humanity*)))))
    

    甚至

    (defun human-address (human)
      (when (stringp human)
        (setq human (gethash human *humanity*)))
      (unless (human-p human)
        (error ...))
      ...)
    

    如果 defgeneric 由于引导问题而尚不可用,或者正在避免作为优化。

    如何:用户级

    系统级指示符不是用户可扩展的。 即,您不能定义自己的包或字符串指示符。

    但是,您可以为自己的类型定义自己的指示符,例如:

    (defclass human ...)
    (defvar *humanity* (make-hash-table ...))
    (defgeneric human-address (human)
      (:method ((human human))
         ...)
      (:method ((name string))
        (human-address (gethash name *humanity*))))
    

    这里string 用作human指示符

    【讨论】:

    • 干杯,似乎很清楚,尽管我可能遗漏了一些东西。如果我是直截了当的,那么指示符是标准化的术语,表示“我们也有这些案例的逻辑”。这对吗?指示符是一个概念,而不是“事物”。此外,我还没有看到在 defgeneric 中定义方法的那种风格,所以谢谢!我想我仍然想知道为什么,如果方法中的方法专业化用作指示符,则 clhs 没有提到 defmethod 或 defgeneric 中的术语,它们通常如此严格
    • 这似乎没有回答这个问题。我还是不知道代号是什么。
    • @Marcin:“什么指示符是”实际上在原始问题中进行了解释 :-) 我添加了一个“什么”部分。
    • “指示符是不是对象的东西”它不是必然对象。有些对象自己指定。
    【解决方案3】:

    对象指示符通常包含多种对象来表示或命名预期对象。

    良好的指示符定义不包括nil(即您可以指定对象),具有不相交的指示符类型,并且指示符通常是或指向预期对象的对象。

    注意:在我看来,指示符是不必要的快捷方式,在使用 REPL 或进行原型设计时非常有用。

    以下是主观分类指示符的非详尽列表。

    良好的指示符(本质上,非零,命名或容器,指示符):

    不太好的指示符:

    • external file format designator

      它的定义故意是开放式的并且依赖于实现,因此由实现来尝试定义好的指示符。除此之外,没关系。

    • package designator

      其定义基于字符串指示符。除此之外,没关系。

    • pathname designator

      我对此有复杂的感觉,主要是因为流不是可靠的路径名指示符。只有文件流和此类流的同义词流是。

      对于可以获取流或自己打开流的给定函数,有时传递已经打开的流以读取或写入并可选择保持打开状态很有用,有时传递要使用的路径名很有用with-open-file(或类似的),所以这里的汇合处丢失了。

      但是,这样的函数可能应该分成两部分,一个显式采用流指示符,另一个显式采用路径名指示符。

    • string designator

      字符串包含一个字符,而不是相反。但是,一个单例字符串可以通过它的单个字符来命名,所以我想这还不错。

      这个指示符不好的一个特殊情况是破坏性操作,它只接受实际的字符串。这是意料之中的,但这是您必须注意的细节,例如如果你从string-upcase 切换到nstring-upcase

    错误的指示符:

    • list designator

      您必须知道(nil) 没有代号。

    • readtable designator

      nil 代表标准可读表,您不能指定可读表。否则,不起眼的nil 不会发出错误信号。

    • stream designator

      nil 用作上下文相关的指示符,在这种情况下您不能指定流。否则,不起眼的nil 不会发出错误信号。

    • stream variable designator

      与流指示符的原因相同。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-01-11
      • 1970-01-01
      • 2021-07-25
      • 2017-03-08
      • 1970-01-01
      • 1970-01-01
      • 2011-06-28
      • 1970-01-01
      相关资源
      最近更新 更多