具体来说:我正在尝试使用 Julia 的 DataFrames 包,特别是带有 names 选项的 readtable() 函数,但这需要一个符号向量。
到目前为止,我在 Julia 语言中只发现了少数几个对符号这个词的引用。似乎符号由“:var”表示,但我还不清楚它们是什么。
旁白:我可以跑
df = readtable( "table.txt", names = [symbol("var1"), symbol("var2")] )
我的两个项目符号问题仍然有效。
Julia 中的符号与 Lisp、Scheme 或 Ruby 中的符号相同。但是,在我看来,这些相关问题的答案并不令人满意。如果您阅读这些答案,似乎符号与字符串不同的原因是字符串是可变的,而符号是不可变的,并且符号也是“interned”——无论这意味着什么。字符串在 Ruby 和 Lisp 中确实是可变的,但它们在 Julia 中不是,这种差异实际上是一个红鲱鱼。符号被拘禁的事实 - 撀爄.e。由用于快速相等比较的语言实现散列 - 也是一个不相关的实现细节。您可以有一个不实习符号的实现,并且语言将完全相同。
那么什么是符号,真的吗?答案在于 Julia 和 Lisp 的共同点——将语言代码表示为语言本身的数据结构的能力。有些人称其为“同音性”(维基百科),但其他人似乎并不认为仅此一项就足以使语言成为同音。但术语并不重要。关键是,当一种语言可以表示它自己的代码时,它需要一种方法来表示诸如赋值、函数调用、可以写为文字值的东西等。它还需要一种方法来表示它自己的变量。即,您需要一种方法来表示“撀联盟数据”foo的左侧:
foo
foo == "foo"
现在我们进入问题的核心:符号和字符串之间的区别在于foo该比较左侧和"foo"右侧之间的区别。左边是一个标识符,它的计算结果是绑定到当前范围内foo的变量的值。foo右边"foo"是一个字符串文字,它的计算结果为字符串值“foo”。Lisp 和 Julia 中的一个符号就是将变量表示为数据的方式。一个字符串只代表它自己。您可以通过应用它们来查看差异eval:
"foo"
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 中构造使用变量的表达式,那么您正在使用符号(无论您是否知道)。例如:
:foo
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:
foo = "bar"
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绑定到 string时执行此操作"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"手动分配,它也行不通。
"foo" = "bar"
这就是符号的本质:在元编程中,符号用于表示变量。当然,一旦您将符号作为数据类型,就很想将它们用于其他用途,例如用作哈希键。但这是对具有另一个主要目的的数据类型的偶然、机会主义使用。
请注意,我不久前不再谈论 Ruby。那是因为 Ruby 不是同音符号:Ruby 并不将其表达式表示为 Ruby 对象。所以 Ruby 的符号类型是一种退化器官——撀翼的剩余改编,继承自 Lisp,但不再用于其最初的目的。Ruby 符号已被用于其他目的——作为散列键,将方法从方法表中提取出来——Ruby 中的符号不用于表示变量。
至于为什么在 DataFrames 中使用符号而不是字符串,这是因为在 DataFrames 中将列值绑定到用户提供的表达式中的变量是一种常见的模式。所以列名是符号是很自然的,因为符号正是你用来将变量表示为数据的东西。目前,您必须写入df[:foo]才能访问该foo列,但在将来,您也许可以改为访问它df.foo。当这成为可能时,只有名称是有效标识符的列才能使用这种方便的语法访问。
df[:foo]
df.foo