6
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

#NervesJPAdvent Calendar 2024

Day 14

Elixirで「過激」にメタプログラミング!マクロでコードに闘魂を注入

Last updated at Posted at 2024-11-05
defmodule FightingSpiritMacro do
  defmacro shout(messages) do
    quote do
      unquote(messages)
      |> Enum.each(& IO.puts("<b><font color=\"red\">$\\huge{#{&1}}$</font></b>"))
    end
  end
end

require FightingSpiritMacro
messages = [
  "元氣ですかーーーッ!!!",
  "元氣があればなんでもできる!",
  "",
  "闘魂とは己に打ち克つこと。",
  "そして闘いを通じて己の魂を磨いていく",
  "ことだと思います。"
]
FightingSpiritMacro.shout(messages)

$\huge{元氣ですかーーーッ!!!}$
$\huge{元氣があればなんでもできる!}$
$\huge{}$
$\huge{闘魂とは己に打ち克つこと。}$
$\huge{そして闘いを通じて己の魂を磨いていく}$
$\huge{ことだと思います。}$

DALL·E 2024-11-04 11.24.56.jpg

はじめに

Elixir 1.17で「過激な」メタプログラミングに挑戦してみませんか?Elixirには、マクロを使ってコードを動的に生成するという強力な機能が備わっています。このマクロ、使い方次第でコードが極めてエレガントに、そして強力に変化します。ただし、慎重に使わないと「過激すぎる」コードになりがちです。まさに「過激な」プロレスです。ストロングスタイルです!

ここでは、Elixirにおけるメタプログラミングの基礎と、マクロでのコード生成方法をシンプルに紹介します。まさに「猪木イズム」で挑むべきテーマです!


メタプログラミングとは?

メタプログラミングとは、コードを生成するためのコードを書くことです。Elixirでは、この目的のためにマクロを利用します。マクロを用いると、コードの繰り返しや冗長性を一気に減らすことができ、柔軟なプログラムが実現します。しかし、その柔軟性ゆえに、プロジェクト全体の可読性が落ちる危険性も伴います。

マクロの基本

まず、シンプルなマクロの基本から見ていきましょう。マクロを定義するには、defmacroを使います。また、マクロの定義にはquoteunquoteが鍵となります。

defmodule FightingMacro do
  defmacro shout do
    quote do
      IO.puts "元氣ですかーーーッ!!!"
    end
  end
end

上記の例では、shoutというマクロを定義しています。このマクロを呼び出すと、まさに「元氣ですかーーーッ!!!」と叫ぶコードが生成されます。

使用例

マクロは通常の関数と同じように使用できますが、呼び出すと「コード自体」が展開されます。

require FightingMacro
FightingMacro.shout() # => 元氣ですかーーーッ!!!

過激なマクロの活用例

まだちっともよさが伝わらないと思いますので、活用例を示します。

マクロの力を過激に発揮させる例として、複数のデータ型に対応した「共通処理」を動的に生成する方法を見てみましょう。例えば、ログを出力するマクロを使うと、どの型のデータでも一貫したログを出力できます。

defmodule LoggerMacro do
  defmacro log(value) do
    quote do
      IO.puts "闘魂注入: #{inspect(unquote(value))}"
    end
  end
end

require LoggerMacro
LoggerMacro.log("123da-") # => 闘魂注入: "123da-"
LoggerMacro.log(123) # => 闘魂注入: 123
LoggerMacro.log(:"strong style") # => 闘魂注入: :"strong style"

LoggerMacroを使わない場合のコードも示しておきます。闘魂注入をタイプする回数に差がでます。この数が多くなればなるほど、コーディング効率の面で差がでるというわけです。マクロを使うとたったの1回ですみます。

LoggerMacroを使わない場合は3回闘魂タイプが必要
IO.puts "闘魂注入: #{inspect("123da-")}"
IO.puts "闘魂注入: #{inspect(123)}"
IO.puts "闘魂注入: #{inspect(:"strong style")}"

マクロを使う際の注意点

マクロは強力なツールですが、「過激」に使いすぎるとコードが複雑になりがちです。以下のポイントに注意して活用しましょう:

  • シンプルに保つ:メンテナンスが難しくなるため、過度なロジックをマクロに詰め込まない。
  • 使いどころを見極める:繰り返し処理や共通ロジックに適した部分のみで利用し、細かい処理には通常の関数を使う。
  • 可読性を重視:他の開発者が理解しやすい形でマクロを設計する。

上記は一般的なマクロを使う際の注意点をまとめています。

公式では以下のページにまとまっています。
Meta-programming anti-patterns


どうやって実行するんだー!? バカヤロー!って方へ

GitHubのアカウントをお持ちの方へお手軽な方法を示しておきます。
PhoenixアプリケーションをGitHub Codespaces上で開発する方法で紹介したGitHub Codespacesを使うという方法です。

記事中で紹介しているphx_devcontainerを使うと、ElixirがインストールされたUbuntuコンテナが立ち上がるので、Ubuntu上で直接開発をしているかのように操作ができます。iexコマンドでREPL(Read-Eval-Print Loop)が立ち上がるのでこの記事のコード例をぜひ試してください。

スクリーンショット 2024-11-02 14.11.07.png

そして気づきましたか。もっともらしく書いていますが、この記事で挙げたLoggerMacroは過激すぎます。単なる関数で間に合います。

defmodule :闘魂ロガー do
  def log(value) do
    IO.puts "闘魂注入: #{inspect(value)}"
  end
end

:闘魂ロガー.log("123da-")
:闘魂ロガー.log(123)
:闘魂ロガー.log(:"strong style")

ムフフ。
虚と実が、入り交じるのがプロレスです。


まとめ

Elixirのマクロを駆使することで、コードに「過激な」エレガンスと効率を注入できます。とはいえ、猪木イズムを忘れず、慎重かつ大胆に挑戦してください!この過激なツールを使いこなすことで、Elixirの可能性をさらに広げ、闘魂をこめたコードが生まれるでしょう。

$\huge{迷わず使えよ、使えばわかるさ!}$

6
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?