Lisp和Erlang原子,Ruby和Scheme符​​号。 他们有多有用?



Answers

原子是文字,常量用自己的名字作为价值。 你看到的是你所得到的,不期待更多。 原子猫的意思是“猫”,就是这样。 你不能玩它,你不能改变它,你不能粉碎它; 它是猫。 处理它。

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

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

这就是说,原子最终会成为更好的语义契合来描述你的代码中的数据,而其他语言将被迫使用字符串,枚举或定义。 它们更安全,更友好,可用于类似的预期结果。

Question

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

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

我没有真正的Lisp或Ruby经验(我知道这些语法,但并没有用在真正的项目中)。 我已经使用Erlang足以适应那里的概念。




我在其他语言(如C)中使用类似概念时遇到的问题可以很容易地表达为:

#define RED 1
#define BLUE 2

#define BIG 1
#define SMALL 2

要么

enum colors { RED, BLUE  };
enum sizes  { BIG, SMALL };

导致如下问题的原因:

if (RED == BIG)
    printf("True");
if (BLUE == 2)
    printf("True");

这两者都没有意义。 原子解决了类似的问题,没有上面提到的缺点。




作为C程序员,我在理解Ruby符号的真正含义时遇到了问题。 在我看到源代码中如何实现符号后,我开始了解。

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

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

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




你说python与原子或符号没有相似之处其实是不对的。 在python中制作像原子一样的对象并不困难。 只要制作好物体即可。 普通的空物体。 例:

>>> red = object()
>>> blue = object()
>>> c = blue
>>> c == red
False
>>> c == blue
True
>>> 

TADA! Python中的原子! 我总是使用这个技巧。 其实,你可以走得更远。 你可以给这些对象一个类型:

>>> class Colour:
...  pass
... 
>>> red = Colour()
>>> blue = Colour()
>>> c = blue
>>> c == red
False
>>> c == blue
True
>>> 

现在,你的颜色是一种类型,所以你可以做这样的事情:

>>> type(red) == Colour
True
>>> 

如果你问我,这实际上是对lispy符号的改进




原子提供快速的平等测试,因为他们使用身份。 与枚举类型或整数相比,它们具有更好的语义(为什么你会用一个数字来表示一个抽象的符号值?),它们并不局限于像枚举这样的一组固定值。

妥协是因为系统需要知道所有存在的实例以保持唯一性,所以它们比字符串更昂贵。 这大多花费时间用于编译器,但是它耗费O(独特原子的数量)中的内存。




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

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

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

> (define x 3)
x
> (define expr '(+ x 1))
expr
> expr
(+ x 1)
> (eval expr #t)
4

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

为了使其工作,Scheme需要能够区分符号和字符串文字。 在上面的例子中, x是一个符号。 它不能被字符串文字替换而不改变其含义。 如果我们接受一个列表'(print x) ,其中x是一个符号并对其进行评估,那么这意味着除'(print“x”)以外其他东西,其中“x”是一个字符串。

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




Related