朱莉娅是什么“符号”?


131

具体来说:我正在尝试使用Julia的DataFrames程序包,特别是使用带有names选项的readtable()函数,但这需要一个符号向量。

  • 什么是符号?
  • 他们为什么会选择一个字符串向量呢?

到目前为止,我只发现了少量的茱莉亚语中的“符号”一词的引用。似乎符号用“:var”表示,但是我对它们的含义还很不清楚。

撇开:我可以跑步

df = readtable( "table.txt", names = [symbol("var1"), symbol("var2")] )

我的两个项目符号问题仍然存在。


3
可以在以下位置找到有关此主题的一些对话:groups.google.com/d/msg/julia-users/MS7KW8IU-0o/cQ-yDOs_CQEJ
jverzani 2014年

Answers:


231

Julia中的符号与Lisp,Scheme或Ruby中的符号相同。但是,我认为这些相关问题的答案并不十分令人满意。如果您阅读了这些答案,似乎符号与字符串不同的原因是字符串是可变的,而符号是不可变的,符号也被“ interned”(无论如何)。字符串在Ruby和Lisp中确实是可变的,但在Julia中却不是,并且实际上是红鲱鱼。插入符号的事实(即,由语言实现进行哈希处理以进行快速相等比较)也是一个不相关的实现细节。您可能会实现一个不使用符号的实现,并且语言将完全相同。

那么,什么是符号呢?答案在于Julia和Lisp的共同点-能够将语言代码表示为语言本身的数据结构。有些人称此为“同音”Wikipedia),但其他人似乎并不认为单单就足以使一种语言具有同音。但是术语并不重要。关键是,当一种语言可以表示自己的代码时,它需要一种表示诸如赋值,函数调用,可以写为文字值的东西之类的方式。它还需要一种表示其自身变量的方式。即,您需要一种方法来表示(作为数据)foo在其左侧:

foo == "foo"

现在,我们进入问题的核心:符号和字符串之间的区别foo是该比较的左侧和"foo"右侧之间的区别。左边foo是一个标识符,它求值foo是当前范围内绑定到变量的值。右边"foo"是字符串文字,其计算结果为字符串值“ foo”。Lisp和Julia中的符号是如何将变量表示为数据。字符串只是代表自己。您可以通过将eval它们应用于它们来查看差异:

julia> eval(:foo)
ERROR: foo not defined

julia> foo = "hello"
"hello"

julia> eval(:foo)
"hello"

julia> eval("foo")
"foo"

该符号:foo求值取决于变量foo绑定的对象(如果有),而"foo"始终仅求值为“ foo”。如果要在Julia中构造使用变量的表达式,则使用符号(无论您是否知道)。例如:

julia> ex = :(foo = "bar")
:(foo = "bar")

julia> dump(ex)
Expr
  head: Symbol =
  args: Array{Any}((2,))
    1: Symbol foo
    2: String "bar"
  typ: Any

除其他事项外,转储的内容显示的是,:foo通过引用代码获得的表达式对象内部有一个符号对象foo = "bar"。这是另一个示例,使用:foo存储在变量中的符号构造一个表达式sym

julia> sym = :foo
:foo

julia> eval(sym)
"hello"

julia> ex = :($sym = "bar"; 1 + 2)
:(begin
        foo = "bar"
        1 + 2
    end)

julia> eval(ex)
3

julia> foo
"bar"

如果您尝试在sym绑定到字符串时执行此操作"foo",则将无法使用:

julia> sym = "foo"
"foo"

julia> ex = :($sym = "bar"; 1 + 2)
:(begin
        "foo" = "bar"
        1 + 2
    end)

julia> eval(ex)
ERROR: syntax: invalid assignment location ""foo""

很清楚,为什么这行不通–如果您尝试"foo" = "bar"手动分配,它也行不通。

这是符号的本质:符号用于表示元编程中的变量。当然,一旦将符号作为数据类型,就很容易将它们用于其他用途,例如哈希键。但这是偶然的,机会主义的数据类型使用,它具有另一个主要目的。

请注意,不久前我不再谈论Ruby。那是因为Ruby不是谐音的:Ruby没有将其表达式表示为Ruby对象。因此,Ruby的符号类型有点像是一种遗迹器官-一种残留的改编,继承自Lisp,但不再用于其原始用途。已将Ruby符号用于其他目的(作为哈希键,将方法拉出方法表),但是Ruby中的符号不​​用于表示变量。

至于为什么在DataFrames中使用符号而不是在字符串中使用符号,是因为这是DataFrames中将列值绑定到用户提供的表达式内的变量的一种常见模式。因此,列名自然是符号,因为符号正是您用来将变量表示为数据的符号。当前,您必须写df[:foo]才能访问该foo列,但是将来,您也许可以访问它df.foo。如果有可能,则使用此方便的语法只能访问名称为有效标识符的列。

也可以看看:


6
实习:在计算机科学中,字符串实习是一种仅存储每个不重复的字符串值的一个副本的方法,该值必须是不变的。插入字符串会使某些字符串处理任务更加节省时间或空间,但代价是在创建或插入字符串时需要更多时间。en.wikipedia.org/wiki/String_interning
xiaodai

一方面,你写作eval(:foo),另一方面eval(sym)。有没有进行有意义的差异eval(:foo)eval(foo)
灰度

非常非常:eval(:foo)给变量foo绑定的值,而eval(foo)对该值调用eval。写作eval(:foo)相当于foo(在全球范围内),eval(foo)就像eval(eval(:foo))
StefanKarpinski
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.