茱莉亚的“象征”是什么?

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

  • 什么是符号?
  • 为什么他们会选择它而不是字符串向量呢?

到目前为止,我在 Julia 语言中只找到了少量关于单词符号的参考。似乎符号是用“ : var”来表示的,但我还不清楚它们是什么。

旁白: 我能跑

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

我的两个问题仍然有效。

29586 次浏览

Julia 中的符号与 Lisp、 Scheme 或 Ruby 中的符号相同。但是,答案对于那些相关的问题 不是很令人满意,在我看来。如果你读过这些答案,你会发现符号与字符串不同的原因似乎是字符串是可变的,而符号是不可变的,而且符号也是“封闭的”——不管这意味着什么。在 Ruby 和 Lisp 中,字符串碰巧是可变的,但在 Julia 中不是,这种差异实际上是在转移注意力。符号被保留的事实——例如,被语言实现散列以进行快速的相等性比较——也是一个不相关的实现细节。你可以有一个实现,不实际符号和语言将是完全相同的。

那么符号到底是什么呢?这个问题的答案在于 Julia 和 Lisp 有一个共同点——在语言本身中将语言代码表示为一个数据结构的能力。有些人称之为 “同性恋”(维基百科) ,但是其他人似乎并不认为仅仅这样就足以使一种语言成为同源语言。但术语并不重要。关键是,当一种语言可以表示它自己的代码时,它需要一种方法来表示诸如赋值、函数调用、可以写成文字值的东西等等。它还需要一种方法来表示自己的变量。也就是说,你需要一种方法来表示-作为数据-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 = "bar"得到的表达式对象内部有一个 :foo符号对象。下面是另一个例子,用存储在变量 sym中的符号 :foo构造一个表达式:

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的形式访问它。当这成为可能时,只有名称为有效标识符的列才能使用这种方便的语法进行访问。

参见:

关于现在的原始问题,即0.21版本(以及将来的版本) DataFrames.jl 允许使用 Symbol和字符串作为列名,因为同时支持这两个并不是问题,而且在不同的情况下,用户可能更喜欢使用 Symbol或字符串。

这里有一个例子:

julia> using DataFrames


julia> df = DataFrame(:a => 1:2, :b => 3:4)
2×2 DataFrame
│ Row │ a     │ b     │
│     │ Int64 │ Int64 │
├─────┼───────┼───────┤
│ 1   │ 1     │ 3     │
│ 2   │ 2     │ 4     │


julia> DataFrame("a" => 1:2, "b" => 3:4) # this is the same
2×2 DataFrame
│ Row │ a     │ b     │
│     │ Int64 │ Int64 │
├─────┼───────┼───────┤
│ 1   │ 1     │ 3     │
│ 2   │ 2     │ 4     │


julia> df[:, :a]
2-element Array{Int64,1}:
1
2


julia> df[:, "a"] # this is the same
2-element Array{Int64,1}:
1
2