ジュリアの「記号」とは?


131

具体的には、私はJuliaのDataFramesパッケージ、特に、namesオプションを指定したreadtable()関数を使用しようとしていますが、これにはシンボルのベクトルが必要です。

  • シンボルとは?
  • なぜ彼らは文字列のベクトルよりもそれを選ぶのでしょうか?

これまでのところ、ジュリア語の単語記号への言及はほんのわずかです。記号は ":var"で表されているように見えますが、記号が何であるかははっきりとはわかりません。

脇:私は走ることができます

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

私の2つの箇条書きの質問はまだ残っています。


3
このトピックに関する会話は、groups.google.com
msg

回答:


231

Juliaのシンボルは、Lisp、Scheme、Rubyと同じです。しかし、私の意見では、これらの関連する質問への回答は本当に満足できるものはありません。これらの回答を読んだ場合、記号が文字列と異なるのは、記号は不変であるのに文字列は変更可能であり、記号も「内部化」されているためです。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
インターン:コンピュータサイエンスでは、文字列のインターンは、各文字列値のコピーを1つだけ格納する方法であり、不変でなければなりません。文字列をインターンすると、一部の文字列処理タスクの時間効率またはスペース効率が向上しますが、文字列が作成またはインターンされるときに、より多くの時間が必要になります。en.wikipedia.org/wiki/String_interning
xiaodai 2017年

ある時点で書いeval(:foo)て、別の時点でeval(sym)。との間に意味のある違いはeval(:foo)ありeval(foo)ますか?
グレースケール

非常にそう:eval(:foo)変数fooがバインドされている値を与えるがeval(foo)、その値に対してevalを呼び出す。書き込みはeval(:foo)ちょうどと等価であるfooので、(グローバルスコープで)eval(foo)のようなものですeval(eval(:foo))
StefanKarpinski
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.