web-dev-qa-db-ja.com

ElixirやJuliaのような言語はどのような意味で同像性ですか?

LISPの同像性は簡単にわかります。

(+ 1 2)

は、引数として+1を使用した2への関数呼び出しであると同時に、+1、および2を含むリストでもあります。それは同時にコードとデータの両方です。

ただし、ジュリアのような言語では、次のようになります。

1 + 2

JuliaでこれをExprに解析できることはわかっています。

:(1 + 2)

そして、ASTを取得して、それを操作できます。

Julia> Meta.show_sexpr(:(1+2)) (:call, :+, 1, 2)

したがって、プログラムのAST in Julia(およびElixir)を操作できます。しかし、LISP-と同じ意味で同像性ですか?anyコードのスニペットは実際には言語自体のデータ構造?

Juliaの1 + 2のようなコードが、LISPの(+ 1 2)が単なるリストであるように、すぐにデータであるかどうかはわかりません。それでは、それはまだホモコニックですか?

38
user2666425

ビル・クリントンの言葉によれば、「それは「言葉」の意味が何であるかによる」。ええと、そうではありませんが、それは「同像性」という言葉の意味が何であるかによって異なります。この用語は十分に物議を醸しているため、ジュリアは同像性であるとは言えません。そのため、この用語が適格かどうかを自分で判断できます。同像性を定義しようとする代わりに、 ケントピットマン (LISPについて1つか2つ知っている)が スラッシュドットインタビュー 2001年に言ったことを引用します。

私はLISPが自らを代表する意欲が好きです。人々はこれを自分自身を表現する能力として説明することがよくありますが、それは間違っていると思います。ほとんどの言語は自分自身を表現することができますが、単にそうする意思がありません。 LISPプログラムはリストで表され、プログラマーはそれを認識しています。それが配列であったかどうかは関係ありません。表現されるのはプログラム構造であり、文字構文ではないことは重要ですが、それを超えると、選択はかなり恣意的です。表現がRight®の選択であることが重要ではありません。この共通の表現で「取引を行う」プログラム操作プログラムの豊富なコミュニティが存在できるように、それが共通の合意された選択であることが重要です。

彼は同像性も定義していません–彼はおそらく私がする以上に定義的な議論に入りたくないでしょう。しかし、彼は問題の核心を切り開いています。言語はそれ自体をどの程度喜んで表現するのでしょうか。 LISPは極端に進んでいます-あなたはそれを避けることさえできません:データとしてのプログラムの表現はちょうどそこに座って、あなたを正面から見つめています。 JuliaはS式構文を使用しないため、データとしてのコードの表現はあまり明白ではありませんが、それほど深く隠されていません。

_Julia> ex = :(2a + b + 1)
:(2a + b + 1)

Julia> dump(ex)
Expr
  head: Symbol call
  args: Array(Any,(4,))
    1: Symbol +
    2: Expr
      head: Symbol call
      args: Array(Any,(3,))
        1: Symbol *
        2: Int64 2
        3: Symbol a
      typ: Any
    3: Symbol b
    4: Int64 1
  typ: Any

Julia> Meta.show_sexpr(ex)
(:call, :+, (:call, :*, 2, :a), :b, 1)

Julia> ex.args[3]
:b

Julia> ex.args[3] = :(3b)
:(3b)

Julia> ex
:(2a + 3b + 1)
_

JuliaコードはExpr型(および記号とアトム)で表され、表面の構文と構造の対応はすぐにはわかりませんが、まだ存在しています。さらに重要なことは、コードは単に生成および操作できるデータであることを人々が知っているため、KMPが述べているように、「プログラム操作プログラムの豊富なコミュニティ」が存在することです。

これは、データ構造としてのJuliaコードの単なる表面的な表現ではありません。これは、Juliaがコードをそれ自体に表す方法です。 REPLに式を入力すると、その式はExprオブジェクトに解析されます。次に、これらのExprオブジェクトはevalに渡されます。これにより、オブジェクトはやや規則的なExprオブジェクトに「下げられ」、型推論に渡され、すべて実装されます ジュリアで 。重要な点は、コンパイラーが、表示されているコードとまったく同じ表現を使用することです。 LISPでも状況はそれほど変わりません。 LISPコードを見ると、実際にはリストオブジェクトは表示されません。これらは、コンピュータのメモリにのみ存在します。表示されているのは、リストリテラルのテキスト表現です。これは、LISPインタプリタが解析してリストオブジェクトに変換し、ジュリアと同じように評価します。 Juliaの構文は、Exprリテラルのテキスト表現と見なすことができます。Exprは、リストよりも一般的なデータ構造ではありません。

詳細はわかりませんが、Elixirも似ていると思います。おそらくJoséがチャイムを鳴らします。

更新(2019)

過去4年以上にわたってこれについてもっと考えてきたので、LISPとJuliaの主な違いは次のとおりだと思います。

  • LISPでは、コードの構文は、そのコードを表すために使用されるデータ構造の構文と同じです。
  • Juliaでは、コードの構文は、そのコードを表すデータ構造の構文とはまったく異なります。

なぜこれが重要なのですか?親ジュリア側では、人々は物事のための特別な構文が好きで、S式構文が不便または不快であると感じることがよくあります。プロLISP側では、(コードを表すために)生成しようとしているデータ構造の構文が通常作成するコードの構文と同じである場合、メタプログラミングを正しく行う方法を理解するのがはるかに簡単です。 。これが、人々がジュリアでマクロを書き込もうとしているときの最良のアドバイスの1つが、次のことを行うことである理由です。

  1. マクロで生成するコードの種類の例を記述します
  2. そのコードで_Meta.@dump_を呼び出して、データ構造として表示します
  3. そのデータ構造を生成するコードを記述します—これがマクロです。

LISPでは、コードの構文はすでにデータ構造の構文と同じであるため、手順2を実行する必要はありません。 Juliaには準引用(LISPで話す)_quote ... end_および:(...)構造があり、コード構文を使用してデータ構造を構築できますが、それでも同じものを使用するほど直接的ではありません。そもそも構文。

関連項目:

50
StefanKarpinski