1. ホーム
  2. julia

[解決済み] Juliaの「シンボル」とは何ですか?

2022-04-23 22:26:09

質問

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

  • シンボルとは何ですか?
  • なぜ、文字列のベクトルではなく、それを選ぶのか?

今のところ、Julia言語でsymbolという単語が使われているのは、ほんの一握りしか見つかっていません。シンボルは":var"で表現されるようですが、それが何であるかは私には到底理解できません。

余談ですが を実行することができます。

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

箇条書きにした2つの質問はまだ有効です。

どのように解決するのですか?

JuliaのシンボルはLisp、Scheme、Rubyと同じです。ただし 答え これらの関連する質問に対して は本当に満足のいくものではありません 私見ですが。これらの回答を読むと、シンボルが文字列と異なる理由は、文字列が変更可能であるのに対してシンボルは不変であり、またシンボルは "interned" - それがどんな意味であれ - ということらしいです。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 シンボルオブジェクトは、コードを引用して得られる式オブジェクトの中にあります。 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のシンボルは、変数を表すために使われることはありません。

なぜDataFrameでは文字列ではなくシンボルが使われるかというと、DataFrameではユーザが用意した式の中でカラムの値を変数に束ねるのが一般的なパターンだからだそうです。つまり、変数をデータとして表現するために使うのがシンボルなのですから、カラム名がシンボルになるのは自然なことなのです。現状では df[:foo] にアクセスするために foo カラムとしてアクセスすることができますが、将来的には df.foo の代わりに それが可能になると、名前が有効な識別子であるカラムだけが、この便利な構文でアクセスできるようになります。

こちらもご覧ください。