Lisp和Erlang Atoms,Ruby和Scheme符​​号.它们有用吗?

Muh*_*uri 61 ruby lisp erlang scheme

在编程语言中使用原子数据类型的功能有多大用处?

一些编程语言具有原子或符号的概念来表示各种常量.我遇到的语言(Lisp,Ruby和Erlang)之间存在一些差异,但在我看来,一般概念是相同的.我对编程语言设计很感兴趣,我想知道原子类型在现实生活中提供了什么价值.其他语言如Python,Java,C#似乎在没有它的情况下做得很好.

我没有Lisp或Ruby的实际经验(我知道语法,但在实际项目中没有使用过).我已经使用Erlang足以用于那里的概念.

I G*_*ICE 53

原子是文字,常量有自己的价值名称.你所看到的就是你得到的,不要期望更多.原子猫的意思是"猫",就是这样.你不能玩它,你不能改变它,你不能把它粉碎成碎片; 这是猫.处理它.

我将原子与以其名称作为值的常数进行比较.您可能使用过以前使用常量的代码:例如,假设我有眼睛颜色的值:BLUE -> 1, BROWN -> 2, GREEN -> 3, OTHER -> 4.您需要将常量的名称与某个基础值匹配.原子让你忘记了潜在的价值观:我的眼睛颜色可以简单地是"蓝色","棕色","绿色"和"其他".这些颜色可以在任何代码段中的任何地方使用:底层值永远不会发生冲突,这样的常量不可能是未定义的!

取自http://learnyousomeerlang.com/starting-out-for-real#atoms

有了这个说法,原子最终是一个更好的语义适合描述代码中的数据,其他语言将被迫使用字符串,枚举或定义.它们更安全,更友好,可用于类似的预期结果.

  • +1回答很好,感谢你的独特网站! (14认同)

Vij*_*hew 37

一个简短的例子,展示了操纵符号的能力如何导致更清晰的代码:(代码在Scheme中,是Lisp的一种方言).

(define men '(socrates plato aristotle))

(define (man? x) 
    (contains? men x))

(define (mortal? x) 
    (man? x))

;; test

> (mortal? 'socrates)
=> #t
Run Code Online (Sandbox Code Playgroud)

您可以使用字符串或整数常量编写此程序.但符号版本具有一定的优势.保证符号在系统中是唯一的.这使得比较两个符号与比较两个指针一样快.这显然比比较两个字符串更快.使用整数常量允许人们编写无意义的代码,如:

(define SOCRATES 1)
;; ...

(mortal? SOCRATES)
(mortal? -1) ;; ??
Run Code Online (Sandbox Code Playgroud)

可能在这个问题的详细答案可以在Common Lisp:一个温和的符号计算简介一书中找到.

  • 穆罕默德,一个原子是一个与整数值相同的字符串常量.当你在代码中看到1时,它只是意味着1; 如果你看到1.3f,则意味着1.3f.同样的原子foo意味着foo. (4认同)

JUS*_*ION 14

原子(在Erlang或Prolog等中)或符号(在Lisp或Ruby等中) - 从这里仅称为原子 - 在您具有没有自然的基础"原生"表示的语义值时非常有用.他们采用C风格的枚举空间如下:

enum days { MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY }
Run Code Online (Sandbox Code Playgroud)

不同之处在于通常不必声明原子并且它们没有潜在的表示来担心.mondayErlang或Prolog中的原子具有"原子monday" 的值,或多或少.

虽然你可以从原子中获得与字符串类型相同的大部分用法,但后者有一些优点.首先,因为保证原子是唯一的(在幕后它们的字符串表示被转换成某种形式的易于测试的ID),所以比较它们比比较等效字符串要快得多.其次,它们是不可分割的.例如,monday无法测试原子是否以其结尾day.它是一个纯粹的,不可分割的语义单元.与字符串表示相比,概念重载更少.

使用C风格的枚举也可以获得很多相同的好处.特别是比较速度,如果有的话,更快.但是......它是一个整数.而且你可以做一些奇怪的事情,比如拥有SATURDAYSUNDAY翻译成相同的值:

enum days { SATURDAY, SUNDAY = 0, MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY }
Run Code Online (Sandbox Code Playgroud)

这意味着你不能相信不同的"符号"(枚举)是不同的东西,因此使代码的推理变得更加困难.太,通过有线协议发送枚举类型是有问题的,因为没有办法区分它们和常规整数.原子没有这个问题.原子不是整数,在幕后看起来永远不会像一个.


Gre*_*Dan 13

作为一名C程序员,我遇到了理解Ruby符号究竟是什么的问题.在看到源代码中如何实现符号后,我开悟了.

在Ruby代码中,有一个全局哈希表,字符串映射到整数.所有红宝石符号都保存在那里.在源代码解析阶段,Ruby解释器使用该哈希表将所有符号转换为整数.然后在内部所有符号都被视为整数.这意味着一个符号仅占用4个字节的内存,并且所有比较都非常快.

所以基本上你可以将Ruby符号视为以非常聪明的方式实现的字符串.它们看起来像字符串,但几乎像整数一样.

创建新字符串时,在Ruby中会分配一个新的C结构来保留该对象.对于两个Ruby字符串,有两个指向两个不同内存位置的指针(可能包含相同的字符串).但是,符号会立即转换为C int类型.因此,无法将两个符号区分为两个不同的Ruby对象.这是实施的副作用.在编码时请记住这一点,这就是全部.

  • 对于原子来说,相同的实现是Erlang,或多或少. (4认同)

Rai*_*wig 12

在Lisp中,符号原子是两个不同且无关的概念.

通常在Lisp中,ATOM不是特定的数据类型.这是NOT CONS的简称.

(defun atom (item)
  (not (consp item)))
Run Code Online (Sandbox Code Playgroud)

ATOM类型也与类型(NOT CONS)相同.

任何不是cons细胞的东西都是Common Lisp中的原子.

SYMBOL是特定的数据类型.

符号是具有名称和标识的对象.符号可以在包中实现.符号可以包含值,函数和属性列表.

CL-USER 49 > (describe 'FOO)

FOO is a SYMBOL
NAME          "FOO"
VALUE         #<unbound value>
FUNCTION      #<unbound function>
PLIST         NIL
PACKAGE       #<The COMMON-LISP-USER package, 91/256 internal, 0/4 external>
Run Code Online (Sandbox Code Playgroud)

在Lisp源代码中,变量,函数,类等的标识符被写为符号.如果读取器读取了Lisp s表达式,它会创建新符号(如果它们未知(在当前包中可用)或重用现有符号(如果它在当前包中可用).如果Lisp读取器读取列表如

(snow snow)
Run Code Online (Sandbox Code Playgroud)

然后它创建了两个cons单元的列表.每个cons单元的CAR指向相同的符号.在Lisp内存中只有一个符号.

另请注意,符号的plist(属性列表)可以存储符号的其他元信息.这可以是作者,源位置等.用户也可以在他/她的程序中使用此功能.

  • 一切都非常有趣和真实,但没有回答这个问题.问题在于讨论"原子数据类型",考虑到OP关于知道Erlang的评论,它将指的是Erlang所谓的原子以及Lisp称之为符号的内容(如果内存服务则是Ruby).线索包含在"一些编程语言中有原子或符号的概念来表示各种各样的常量.我遇到的语言之间存在一些差异(Lisp,Ruby和Erlang),但在我看来,一般概念是一样的." (3认同)
  • @JUST MY正确的观点:OP在Lisp和Erlang中谈论'Atom'.还有关于Ruby和Scheme中的符号.我解释说ATOM和符号没有关系,所以他的问题是有限的.然后我解释了Lisp中ATOM和Symbols之间的区别,以及Symbols提供的内容. (3认同)
  • 谢谢.我在Lisp中混淆了术语.我在考虑字母数字原子,它们是Lisp中的正确符号.虽然我的问题是关于Erlang符号,但你的答案绝对有助于消除我的困惑. (2认同)

Han*_*wak 6

在Scheme(以及Lisp系列的其他成员)中,符号不仅有用,它们也是必不可少的.

这些语言的一个有趣的特性是它们是同质的.Scheme程序或表达式本身可以表示为有效的Scheme数据结构.

一个例子可能会使这更清楚(使用Gauche Scheme):

> (define x 3)
x
> (define expr '(+ x 1))
expr
> expr
(+ x 1)
> (eval expr #t)
4
Run Code Online (Sandbox Code Playgroud)

这里,expr只是一个列表,由符号+,符号x和数字1组成.我们可以像其他任何一样操纵这个列表,传递它等等.但是我们也可以评估它,在这种情况下它将被解释为代码.

为了使其工作,Scheme需要能够区分符号和字符串文字.在上面的示例中,x是符号.在不改变含义的情况下,不能用字符串文字替换它.如果我们取一个列表'(print x),其中x是一个符号,并对其进行评估,这意味着除了'(print"x")之外的其他内容,其中"x"是一个字符串.

顺便说一下,使用Scheme数据结构表示Scheme表达式的能力不仅仅是一种噱头; 将表达式作为数据结构读取并以某种方式对其进行转换是宏的基础.