関数とは、ある量と何か1つの量とを結びつける機能、作用、システム、ルール、関係のことです。
(関「数」と呼びますが、「数」そのもののことではありません。)
17世紀後半のドイツで、哲学者・数学者のライプニッツが生み出した概念です。
次の図の量 $x\,,y$ と関数 $f$ について、次のようないくつかの捉え方ができます。

- $f$ には $x$ を放り込むと $y$ に変換して返す機能が備わっている。
- $f$ は入力を $x$ 、出力を $y$ とするシステムである。
- $x$ と $y$ には $f$ という関係がある。
これらは同じことを言い換えているだけですが、1・2番目には原因と結果という変化の前後に注目している印象を受けます。(実際に物理・工学の分野ではこちらの観点が主です。)
一方で、3番目はニュアンスがやや違い、$x\,,y$ よりも関係 $f$ に注目している印象を受けます。(代数学などのより抽象的な数学の分野ではこちらの観点が強いように思います。)
そして、これまでの内容を数式で表したものが次の等式です。
\begin{align}
y=f(x)\,.\label{func}
\end{align}
入力と出力のうち、片方の量を自由に変化させると、もう一方の量は関数 $f$ によって自動的に決まってしまいます。
このような量のことをそれぞれ、独立変数と従属変数と呼びます。
慣習的には $x$ を独立変数、$y$ を従属変数とすることが多いですが、どの文字がどれに対応するのかは把握しておく必要があります。
プログラミング言語における「関数」は、今回対象にしている数学における「関数」とは異なる概念であるという主張をよく見かけます。
実際、それは正しいとは思いますが、初学者が関数のことを「機能・システム」だとなんとなく捉える場合には、どちらも同じように解釈した方が混乱も少ないと思います。
誤解から深い理解や別の分野への発想が進む可能性があるメリットを考慮して、本サイトではプログラミングの関数もまとめて関数として扱います。
関数の合成
次に、関数の合成について説明します。
いま、ある量 $x$ を関数 $f$ で $y$ に変換させ、その $y$ を関数 $g$ で $z$ に変換することを考えます(次図)。

ここで、この図全体で最初の入力である $x$ について着目してみます。
\eqref{func}の関係を使うと、$y=f(x)\,,z=g(y)$ という関係から、$z=g(f(x))$ が出てきます。
ここで、関数 $f\,,g$ を合成して得られる関数を $g\circ f$ と書くことにします。
すなわち、 $z=g\circ f(x)=g(f(x))$ であり、この関数の入力は $x$ で出力は $z$ です(次図)。

関数の合成はすごい力を持っています。
なぜなら、小さな関数の性質がわかれば、それらの合成関数として作られた(と解釈できる)複雑な現象やシステムも理解することができるからです。
このような考え方は現代科学の様々な分野でよく見られ、要素還元主義的であると言われます。
17世紀フランスの哲学者・数学者デカルトは『方法序説』において「困難は分割せよ」と述べています。
関数の合成の具体例
関数や関数の合成の具体例はいくらでもありますが、1つ変わった具体例を考えてみましょう。
いまここに、ロボットがあります。
このロボットには次の2つの機能が備わっていて、それぞれ対応するボタンを押せばその通りに行動し、動作を停止します。
- 機能1:一定時間まっすぐ歩き続ける。
- 機能2:その場で180度回転して進む向きを逆にする。
この設定を数式で表したとき、関数の合成がどうなるのか見てみましょう。
まず、ロボットが止まったときの場所の名前を $\text{A}\,,\text{B}\,,\text{C}$ などと付けます。
そして、ロボットの状態を $x$ と表すことにして、「ロボットが $\text{A}$ にいる」を $x\in A$と表すことにします。
このとき、ロボットの持つ2つの機能を、それぞれ抽象的に次のように書くことにします。
- 機能1: $f$ と表す。
出力 $y=f(x)\, (x\in A)$ は、$y\in B$ となる。($A$ と $B$ を $C$ と $A$ などの異なる2つの文字に入れ替えても同じ。)
これは、関数 $f$ 「機能1:一定時間まっすぐ歩き続ける」によってロボットが移動するので、入力 $x$「場所 $\text{A}$ にいるロボットの状態」は出力 $y$「場所 $\text{B}$ にいるロボットの状態」になるということを述べています。 - 機能2: $g$ と表す。
出力 $y=g(x)\, (x\in A)$ は、$y\in A$ となる。($A$ と $B$ や $C$ を入れ替えても同じ。)
これは、関数 $g$ 「機能2:その場で180度回転して進む向きを逆にする」によってロボットがその場に留まるので、入力 $x$「場所 $\text{A}$ にいるロボットの状態」は出力 $y$「場所 $\text{A}$ にいるロボットの状態」になるということを述べています。
さて、スタート地点を $\text{A}$ として、ロボットの移動先を追ってみましょう。

- $g\circ f(x)$
ロボットは $f$ によって $\text{A}$ から $\text{B}$ に移動して、$g$ によってその場で回転する。
なので最終的な移動先は $\text{B}$ となります。 - $f\circ g(x)$
ロボットは $g$ によってその場で回転して向きを変え、 $f$ によって $\text{A}$ から $\text{C}$ に移動する。
なので最終的な移動先は $\text{C}$ となります。
このように、ロボットの最終的な移動先が異なっているため、合成関数は $g\circ f(x)\neq f\circ g(x)\,(x\in A)$ となります。
この例で少し触れたように、実は関数を扱う際には定義域をセットで考える必要があります。
これは、関数の入力と出力がどこからどこへいくのか、どのような性質をもつ量であればいいのかについての記述です。
定義域については今後書きます。
コメント