はじめに
「冪等(べきとう / idempotent)」という言葉、ふんわりとは分かるけど、いざ説明しようとすると言葉に詰まる——そんな概念のひとつだと思います。
漢字が難しくて何だかやっかいな言葉に見えるし。
「安全(safe)」「純粋(pure)」。
これらの言葉と一緒に理解することで、私は、「冪等」の輪郭を掴めた感覚があります。
この記事は冪等を単体で説明しません。
周辺の言葉との境界を引きながら、冪等の輪郭を浮かび上がらせるという進め方をします。
そしてその過程で、Web API(HTTP)と関数型プログラミングという2つの世界に、冪等が同じ形で顔を出していることも見えてきます。
まず、出てくる言葉を揃えておく
境界を引く前に、これから登場する言葉を先に定義しておきます。今は「ふーん」と眺めるだけで大丈夫です。この後、ひとつずつ冪等と並べていきます。
- 冪等(idempotent): その操作を2回以上繰り返しても、1回だけやったときと最終結果が変わらないこと。
-
安全(safe): HTTP リクエストの意味として、対象リソースを変更しないこと。代表例は
GET。 -
純粋(pure): 副作用がなく、同じ入力には必ず同じ出力を返すこと。(関数型プログラミングの概念)
- 副作用(side effect): 関数の外側の世界に影響を与えること。たとえば状態の更新、I/O、ログ出力など。
注目してほしいのは、定義の見ている場所が違うことです。
副作用・安全・純粋は、どれも「外の世界との関わり方」を見ています。
一方、冪等だけは「繰り返したらどうなるか」を見ている。
この「見ている場所の違い」が、記事全体を通しての鍵になります。
冪等の定義を、エアコンで掴む
主役の冪等から、もう少し具体的に掴んでおきます。
冪等 = その操作を2回以上繰り返しても、1回だけやったときと最終結果が変わらないこと。
エアコンのリモコンで考えると分かりやすいです。
「冷房」ボタンは冪等です。
冷房モードのときにもう一度「冷房」を押しても、冷房のまま。
何回押しても結果は「冷房」で変わりません。
エアコンに依るところはあるかもしれません。少なくとも、私のエアコンは、そうです。
一方、温度の「+」ボタンは冪等ではありません。
押すたびに設定温度が上がっていくので、繰り返すと結果が変わります。
同じリモコンの上に、冪等なボタンと、冪等じゃないボタンが並んでいるわけですね。
この「繰り返しても結果が変わらないか?」が、この記事のあいだ、ずっと主役になる軸です。
では、「副作用」、「安全」、「純粋」と、ひとつずつ並べていきます。
純粋
まず「純粋」と並べます。
純粋の定義は「副作用がなく、同じ入力には必ず同じ出力を返すこと」。
そして、副作用は「関数の外側の世界に影響を与えること」でした。
ここで、「純粋 = 冪等」と言えそうな気がします。
でも、言えません。例を見てみましょう。
「受け取った数に1を足して返す」だけの、小さな関数を考えます。
f(3) = 4
この関数は外の世界に影響を与えません。副作用はゼロです。
そして、3を入れたら必ず4を返す。
副作用がなく、同じ入力には必ず同じ出力を返します。
つまり、純粋な関数。
でも、冪等じゃないんです。試しに2回続けてかけてみましょう。
1回: 3 → 4
2回: 3 → 4 → 5
2回関数を通すと 5 になってしまって、1回かけた 4 とは違います。
副作用がないのに、繰り返すと結果が変わる
—— つまり、「純粋か」と「冪等か」は、別の軸なんですね。
片方からもう片方は決まらない。
安全
次に「安全(safe)」と並べます。
安全は「HTTP リクエストの意味として、対象リソースを変更しないこと」でした。
これも「冪等=安全」と言えそうな気がします。でも、やっぱり言えません。
SNS(Xなど)の投稿を削除する操作を考えます。
これは対象リソースを変更する操作です(投稿が消えるので)。
だから「安全」ではありません。でも、冪等ではあるのです。
1回目の削除: 投稿42 → 消える
2回目の削除: もう無いので、何も起きない → 消えたまま
2回目を実行しても、最終的な状態は「投稿42が無い」で、1回目と同じ。
安全ではない(対象リソースを変更する)のに、冪等です。
—— つまり、「外の世界との関わり方」と「繰り返したらどうなるか」は、別の軸です。
2つの軸を、表で確かめる
「外の世界との関わり方」と「冪等」、この2つが別の軸だということを、表で確かめてみます。
縦が「外の世界にどう関わるか」、横が「繰り返しても同じか」です。
ただし、HTTP と関数型では、縦軸で見ている対象が少し違います。
HTTP では対象リソースを変更するか、関数型では外部世界に依存・影響するかを見ています。
ここでは、説明のためにどちらも「外の世界との関わり方」として並べています。
| 冪等(繰り返しOK) | 冪等じゃない(繰り返すと変わる) | |
|---|---|---|
| 外の世界を変えない / 影響しない |
GET(取得) / 絶対値を返す関数 |
「1を足す」関数 |
| 外の世界を変える / 影響する |
PUT(置き換え), DELETE(削除) |
POST(新規作成) / カウントを増やす操作 |
ポイントは、4つのマスすべてに例が入ることです。
もし「外の世界を変えるか」と「冪等か」が同じ軸なら、右上と左下のマスは空っぽになるはずです。
でも、両方とも埋まっています。だから、2つは別の軸なんです。
特に、右上の「1を足す関数」と、左下の「削除」。
この2マスが「外の世界との関わり方」と「冪等」は別物だということをよく表しています。
ここまでで、冪等の輪郭がだいぶはっきりしてきました。
冪等は「繰り返したらどうなるか」だけを見ている軸で、「状態を変えるか」とは独立している。
ここから先は、この軸が、Web API の世界と関数型の世界で、それぞれ何と呼ばれているかを見ていきます。冒頭で揃えた safe と pure が、ここで縦軸として効いてきます。
HTTP の世界では
HTTP には、操作の性質を表す言葉が2つあります。さっきの表の縦軸と横軸に、ちょうど対応しています。
-
安全(safe): HTTP リクエストの意味として、対象リソースを変更しない。
GETが当てはまる。→ 縦の軸。 -
冪等 (idempotent): 何回実行しても、サーバー側の意図された状態が同じ。
GET,PUT,DELETEが当てはまる。→ 横の軸。
少し細かいことを言うと、HTTP の安全は、「そのリクエストの意味として、対象リソースを変更しない」という性質です。
ログやキャッシュのような副次的な変化まで一切禁止する、という意味ではありません。
DELETE(削除)は、対象リソースを変更するので safe ではありません。
一方で、何回消しても「無い」状態に落ち着くので冪等です。
ひとつ、冪等を正確に掴むうえで大事な注意があります。
冪等が約束するのは「レスポンスが毎回同じ」ことではなく、リクエストを1回送った後と複数回送った後で、サーバー側の意図された状態が同じになることです。
たとえば PUT /profile で名前を「Alice」に置き換える操作は、1回送っても2回送っても最終的な名前は「Alice」です。
だから PUT は冪等です。
削除の1回目は「消しました(成功)」、2回目は「そんなのもう無いよ(404)」という、違う返事でいいんです。
状態(投稿が無い)は同じなので、ちゃんと冪等。
ここを「レスポンスが同じこと」だと取り違えると、DELETE が冪等に見えなくなってしまいます。
なお、POST は HTTP メソッドの性質としては冪等ではありません。
同じ POST /posts を2回送ると、投稿が2つ作られるかもしれないからです。
ただし実務では、Idempotency-Key などを使って、特定の POST endpoint をアプリケーション側で冪等に設計することがあります。
これは「POST というメソッドが仕様上冪等」という意味ではなく、「その API が重複実行に耐えるように作られている」という意味です。
関数型プログラミングの世界では
関数型でも、似た構造の2つの軸が出てきます。
- 純粋(pure): 冒頭で定義した通り、副作用がなく、同じ入力に同じ出力を返すこと。→ 縦の軸(状態を変えない側)。
- idempotent(冪等): 同じ操作を2回かけても、1回と結果が同じ。→ 横の軸。
関数型でいう冪等は、もう少し形式的に書くとこうです。
f(f(x)) = f(x)
つまり、ある値 x に関数 f を1回かけた結果と、その結果にもう一度 f をかけた結果が同じになる、ということです。
たとえば絶対値を返す関数 abs は冪等です。
abs(-3) = 3
abs(abs(-3)) = abs(3) = 3
1回かけても 3、2回かけても 3。だから abs(abs(x)) = abs(x) が成り立ちます。
小数点以下を切り捨てる関数も同じで、3.7 → 3、もう一度かけても 3 のままです。
一方で、「1を足す」関数 inc は冪等ではありません。
inc(3) = 4
inc(inc(3)) = inc(4) = 5
1回かけた結果と、2回かけた結果が違います。つまり inc(inc(x)) = inc(x) にはなりません。
図にすると、この違いがはっきりします。abs は何回かけても値が動かない一方、inc はかけるたびに先へ進んでいきます。
ここで大事なのは、abs も inc もどちらも純粋な関数だということです。
外の世界に影響を与えず、同じ入力には同じ出力を返します。
それでも、abs は冪等で、inc は冪等ではありません。
—— つまり、純粋であることは、冪等であることを意味しない。「純粋」は冪等の隣の言葉ではあるけど、別の軸なんですね。
ちなみに、関数型の pure と HTTP の safe は、どちらも「本命の対象を壊さない・書き換えない」という方向を向いた言葉です。
ただし同じではありません。
safe は「HTTP リクエストの意味として、対象リソースを変更するか」を見ています。
pure は「関数が外部世界に依存・影響するか」を見ています。
2つの世界は、実は同じ軸だった
ここまで、冪等を「副作用」「安全」「純粋」という隣の言葉と並べながら、その輪郭をはっきりさせてきました。最後に、面白いことが見えてきます。
冪等(idempotent) という横の軸は、Web API の世界と関数型の世界をまたいで、同じ構造を持っています。
もともとは数学の言葉で、「2回やっても1回と同じ」という意味です。
- 関数型は、これをそのまま関数に当てはめている(絶対値、切り捨て)。
- HTTP は、これを「操作した後のサーバーの状態」に当てはめている(
PUT,DELETE)。
一方で、縦の軸(外の世界との関わり方)は、世界ごとに名前が違います。
HTTP では safe、関数型では pure。見ている対象が違うので、名前も違うわけですね。
構造で見ると、こうなっています。縦の軸だけが世界ごとに名前が分かれ、横の軸(冪等)は1本のまま両方を貫いています。
「繰り返しても同じ(= 冪等)」という構造だけが、両方の世界をまたいで通っています。
冪等は「HTTPメソッドの分類のひとつ」でも「関数型だけの用語」でもなく、「繰り返しても変わらない」という1本の軸として、複数の世界に現れる概念なんです。
この軸を持つと、何が変わるのか
冪等を、隣の言葉ときちんと区別したうえで独立した軸として持てると、何かを設計するとき、問いを2つに分けて考えられるようになります。
- この操作(関数)は、外の世界を変えるか / 影響するか? → safe / pure の話
- この操作(関数)は、繰り返しても大丈夫か? → idempotent の話
この2つを別々に問えると、「状態は変えるけど、繰り返しに強くしておきたい(削除や置き換えのような設計)」とか「副作用はないけど、繰り返すと値がたまっていく計算」みたいなケースを、混同せずに扱えます。
「冪等?」と、「副作用ある?」とを別々の軸として持つ。
それだけで、API を作るときも、関数を書くときも、判断の解像度が一段上がります。
おわりに
冪等という言葉は、単体で覚えようとすると、するっと手からこぼれます。
「繰り返しても同じ」という定義は分かっても、安全や純粋とどう違うのか、と聞かれると詰まる。
でも、隣の言葉と並べて境界を引いていくと、輪郭がはっきりしてきます。副作用とも違う、安全とも違う、純粋とも違う。冪等が見ているのは「繰り返したらどうなるか」だけ。そして、その軸は HTTP にも関数型にも、同じ形で存在している。
次に API を設計するとき、あるいは関数を書くとき。
「これは外の世界や対象リソースに影響する?」「これは繰り返せる?」と、2つに分けて問うてみてください。
冪等という言葉が、さっきより少しくっきり見えるはずです。

