<commit_before>---
version: 1.0.2
title: メタプログラミング
---

メタプログラミングとはコード自体にコードを記述させる機能です。Elixirでは、メタプログラミング機能によりニーズに合わせて言語を拡張し、動的にコードを変更することができます。Elixirが内部でどのように表現されるかを見ることから始めましょう。次にそれを修正する方法を学び、そして最終的に拡張するためにこの知識を使用してみましょう。

注意事項: メタプログラミングはトリッキーで、どうしても必要な場合にのみ使用してください。過度の使用は、ほぼ確実に、理解及びデバッグすることが困難な複雑なコードにつながります。

{% include toc.html %}

## Quote

メタプログラミングするための最初のステップは、式が表現される方法を理解することです。Elixirでは抽象構文木(AST)（コードの内部表現)は、タプルで構成されています。タプルは、右記3つの要素で構成されます : 関数名、メタデータ、関数の引数

これらの内部構造を見るために、Elixirは `quote/2` 関数を提供しています。 `quote/2` を使い、Elixirのコードをその基礎となる表現に変換することができます:

```elixir
iex> quote do: 42
42
iex> quote do: "Hello"
"Hello"
iex> quote do: :world
:world
iex> quote do: 1 + 2
{:+, [context: Elixir, import: Kernel], [1, 2]}
iex> quote do: if value, do: "True", else: "False"
{:if, [context: Elixir, import: Kernel],
 [{:value, [], Elixir}, [do: "True", else: "False"]]}
```

注意点として、最初の3つはタプルを返しません。以下の５つのリテラルはquoteされた時に自分自身を返します:

```elixir
iex> :atom
:atom
iex> "string"
"string"
iex> 1 # All numbers
1
iex> [1, 2] # Lists
[1, 2]
iex> {"hello", :world} # 2 element tuples
{"hello", :world}
```

## Unquote

今、コードの内部構造を検索することができましたが、どのようにそれを修正しましょう？新しいコードまたは値を注入するために、 `unquote/1` を使用します。式をunqoteすると、それが評価され、ASTに注入されます。 `unquote/1` を実証するために、いくつかの例を見てみましょう:

```elixir
iex> denominator = 2
2
iex> quote do: divide(42, denominator)
{:divide, [], [42, {:denominator, [], Elixir}]}
iex> quote do: divide(42, unquote(denominator))
{:divide, [], [42, 2]}
```

最初の例では変数 `denominator` は、結果として得られるASTが変数にアクセスするためのタプルを含んでいるようにquoteされています。 `unquote/1` の使用例では生成されたコードに `denominator` の値が含まれています。

## マクロ

`quote/2` と `unquote/1` を理解すれば、マクロに飛び込む準備が整います。マクロのようなすべてのメタプログラミングは、慎重に使用する必要があることを覚えておくことが重要です。

最も簡単な用語であるマクロは、私たちのアプリケーションコードに挿入されるquoteされた式を返すように設計された特別な機能です。マクロは関数のように呼び出されるのではなく、quoteされた表現に置き換えられるのだということを想像してみてください。マクロで、私たちはElixirを拡張し、動的に私たちのアプリケーションにコードを追加するために必要なすべてを持っています。

`defmacro/2` を使用してマクロの定義から始めます。 `defmacro/2` 自身がマクロであり、Elixrの多数の機能がマクロで出来ています。例として、 `unless` をマクロとして実装します。マクロはquoteされた式を返す必要があることを忘れないでください:

```elixir<commit_msg>[JA] Fix typo in Metaprogramming (#2281)<commit_after>---
version: 1.0.2
title: メタプログラミング
---

メタプログラミングとはコード自体にコードを記述させる機能です。Elixirでは、メタプログラミング機能によりニーズに合わせて言語を拡張し、動的にコードを変更することができます。Elixirが内部でどのように表現されるかを見ることから始めましょう。次にそれを修正する方法を学び、そして最終的に拡張するためにこの知識を使用してみましょう。

注意事項: メタプログラミングはトリッキーで、どうしても必要な場合にのみ使用してください。過度の使用は、ほぼ確実に、理解及びデバッグすることが困難な複雑なコードにつながります。

{% include toc.html %}

## Quote

メタプログラミングするための最初のステップは、式が表現される方法を理解することです。Elixirでは抽象構文木(AST)（コードの内部表現)は、タプルで構成されています。タプルは、右記3つの要素で構成されます : 関数名、メタデータ、関数の引数

これらの内部構造を見るために、Elixirは `quote/2` 関数を提供しています。 `quote/2` を使い、Elixirのコードをその基礎となる表現に変換することができます:

```elixir
iex> quote do: 42
42
iex> quote do: "Hello"
"Hello"
iex> quote do: :world
:world
iex> quote do: 1 + 2
{:+, [context: Elixir, import: Kernel], [1, 2]}
iex> quote do: if value, do: "True", else: "False"
{:if, [context: Elixir, import: Kernel],
 [{:value, [], Elixir}, [do: "True", else: "False"]]}
```

注意点として、最初の3つはタプルを返しません。以下の５つのリテラルはquoteされた時に自分自身を返します:

```elixir
iex> :atom
:atom
iex> "string"
"string"
iex> 1 # All numbers
1
iex> [1, 2] # Lists
[1, 2]
iex> {"hello", :world} # 2 element tuples
{"hello", :world}
```

## Unquote

今、コードの内部構造を検索することができましたが、どのようにそれを修正しましょう？新しいコードまたは値を注入するために、 `unquote/1` を使用します。式をunquoteすると、それが評価され、ASTに注入されます。 `unquote/1` を実証するために、いくつかの例を見てみましょう:

```elixir
iex> denominator = 2
2
iex> quote do: divide(42, denominator)
{:divide, [], [42, {:denominator, [], Elixir}]}
iex> quote do: divide(42, unquote(denominator))
{:divide, [], [42, 2]}
```

最初の例では変数 `denominator` は、結果として得られるASTが変数にアクセスするためのタプルを含んでいるようにquoteされています。 `unquote/1` の使用例では生成されたコードに `denominator` の値が含まれています。

## マクロ

`quote/2` と `unquote/1` を理解すれば、マクロに飛び込む準備が整います。マクロのようなすべてのメタプログラミングは、慎重に使用する必要があることを覚えておくことが重要です。

最も簡単な用語であるマクロは、私たちのアプリケーションコードに挿入されるquoteされた式を返すように設計された特別な機能です。マクロは関数のように呼び出されるのではなく、quoteされた表現に置き換えられるのだということを想像してみてください。マクロで、私たちはElixirを拡張し、動的に私たちのアプリケーションにコードを追加するために必要なすべてを持っています。

`defmacro/2` を使用してマクロの定義から始めます。 `defmacro/2` 自身がマクロであり、Elixrの多数の機能がマクロで出来ています。例として、 `unless` をマクロとして実装します。マクロはquoteされた式を返す必要があることを忘れないでください:

```elixir
{'fraction_non_alphanumeric': 0.13782207097715118, 'fraction_numerical': 0.020904229460379193, 'mean_word_length': 9.339195979899497, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 29, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5145387', 'n_tokens_mistral': 3097, 'n_tokens_neox': 2764, 'n_words': 284}