言語が同図像性を持つとはどういうことか

# 「同図像性を持つRedは至高の言語なのよ、ウヒャヒャ」（冤罪）

Red言語が好きでずっとチェックしています。
が、先日妻にRedのどこがいいのか聞かれ、説明が難しかったので笑ってごまかしたら[変態扱い](https://twitter.com/rikubo_hatena/status/1143872603368509440)されてしまいました。
名誉回復のためにRedの最大の特性である同図像性とは何がよいのかを説明します。

## 同図像性とは

Wikipediaを見てみましょう
<img width="694" alt="Wikipedia同図像性.PNG" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/110552/ad5e54dd-b42f-0f8e-6358-c81ad399359b.png">
ない・・・だと・・・
※2019年8月24日現在

なんかもうWikipediaに載っていない特性を崇めているという時点で、自分が変態と認めざるを得ない気もしますが、英語版のウィキペディアなら載っていたのでセーフということで。

[英語版Wikipedia：Homoiconicity](https://en.wikipedia.org/wiki/Homoiconicity)

> A language is homoiconic if a program written in it can be manipulated as data using the language, and thus the program's internal representation can be inferred just by reading the program itself.
> （中略）
> This property is often summarized by saying that the language treats "code as data".

以下筆者翻訳

> ある言語が同図像性を持つということは、その言語で書かれたプログラムが、その言語自身によってデータとして操作できるということである。それは同時に、プログラムの内部表現がプログラム自体を見ることで理解できるということでもある。
> （中略）
> この性質はしばしば言語が「コードをデータとして扱う」と表現される。

**たまらんですね。（病気）**

## つまりどういうことだってばよ

例をあげて説明します。

### C#の場合

たとえば、C#で配列を作る時、最もシンプルなのはコレクション初期化子を使う以下のコードです。

```cs
var messages = new[]
{
	"おはよう！",
	"Good morning!",
	"Bonjour!"
};
```

これでmessages変数に文字列の配列が保持されるわけですが、ではmessages変数に保持されている配列のインスタンスから配列の初期化に使った上記のコードを得ることはできるでしょうか？

```cs
// ToString()しても型名が出るだけ
messages.ToString();
// System.String[]

// 当たり前だがXMLシリアライズしたら完全に別物の文字列になる
var serializer = new XmlSerializer(typeof(string[]));
var m = new MemoryStream();
serializer.Serialize(m, messages);
Encoding.UTF8.GetString(m.ToArray());
/*
<?xml version="1.0"?>
<ArrayOfString xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
	<string>おはよう！</string>
	<string>Good morning!</string>
	<string>Bonjour!</string>
</ArrayOfString>
*/
```

多くの言語ではこれは困難です。
一度変数にセットされたオブジェクトのインスタンスは、基本的にはそこから元の「コード」を得ることはできません。インスタンスを「データ」とみなすのであれば、C#では`コード⇒データは不可逆である`と言えます。

しかしRedではできます。できますというか根本的に、変数[^1]にデータをセットしてもデータはその時のソースコードそのままで保持されます。これはRedがプログラミング言語であるとともに、独自のデータ表現言語でもあるためです。
以下はRedのコンソールでのサンプルです。
なお、Redではセミコロンがコメントになります。

[^1]: 本来はRedには「変数」という用語はないですが、この記事ではそこは本筋ではないので変数と呼称することにします。

```red
messages: [
	"おはよう！"
	"Good morning!"
	"Bonjour!"
]
; == [
;   "おはよう！"
;   "Good morning!"
;   "Bonjour!"
;]

; 後で参照しても表現はまったく変わらない。
; 初期化した時のソースコード相当のものがそのまま得られる。
messages
; == [
;   "おはよう！"
;   "Good morning!"
;   "Bonjour!"
;]
```

上の例のようにRedでは、コードがデータとして扱われる故に、C#であったような`コード⇒データの不可逆性`がありません。一度変数に入れられたコードは、そのままの形で後から参照することが可能です。

## それ何がうれしいねん

待って。まだ帰らないで。

コードとデータの区別がないと何がうれしいのか説明します。最もよく言われるのは、メタプログラミングが簡単に行えるということです。メタプログラミングとは、プログラミングでプログラムを操作することです。たとえば、以下のように挨拶を3ヶ国語で順番に出力するコードを考えます。

```greetings.red
; 挨拶のblock!（配列のようなもの）
messages: [
	"おはよう！"
	"Good morning!"
	"Bonjour!"
]

; 列挙して順番にコンソール出力
foreach message messages [print message]
```

上記のコードを実行すると、

* おはよう！
* Good morning!
* Bonjour!

と3ヶ国語で挨拶されます。
Redを使って、上記のRedコードを4ヶ国語で挨拶するコードに変更してみましょう。元のコードは`greetings.red`ファイルとして保存されているとします。

```red
; loadでコードの内容を読み込み、code変数にセット
code: load %greetings.red
; == [messages: [
;     "おはよう！"
;     "Good morning!"
;     "Bonjour!"
; ]
;     foreach message me...

; code変数の2番目の要素（挨拶のブロック）に対してappend（要素の追加）を実行
append code/2 "早上好！"
; == [messages: [
;     "おはよう！"
;     "Good morning!"
;     "Bonjour!" "早上好！"
; ]
;     foreach mess...

; 修正したcodeを実行するにはdoに渡す
do code
; おはよう！
; Good morning!
; Bonjour!
; 早上好！
```

上記のように、読み込んだコードを変数に保持した後、インデクサ（Redでは`/`がインデクサ的なものです）で変更したい箇所を指定して`append`で要素を追加するだけです。`append`は配列的なもの[^2]の要素を追加する関数です。もし変更したコードをファイルに保存したければ、以下のようにするだけでOKです。

[^2]: 引数にseries!データ型が渡せるようになっており、これは他の言語で言うところの配列のようなものです。

```red
save %greetings2.red code

; 以下の内容がgreetings2.redとして保存される。
;
; messages: [
; "おはよう！"
; "Good morning!"
; "Bonjour!" "早上好！"
; ]
; foreach message messages [print message]
```

あるいは、挨拶の1番目をドイツ語に差し替えたかったら、以下のようにすればOKです。

```red
; コードの2番目の要素（挨拶のblock!）の1番目を変更
code/2/1: "Guten Morgen!"
; == "Guten Morgen!"

; 変更後のコードを実行
do code
; Guten Morgen!
; Good morning!
; Bonjour!
; 早上好！
```

このように、Redではコードによってコードを操作することが簡単に行えます。この性質のおかげで、Redは非常に強力なメタプログラミング能力を持っています。今後の記事で、もう少し実践的な例などご紹介できればと思います。