サポンテ 勉強ノート

サポンテの勉強ノート・読書メモなどを晒します。

関数ってなに? --- プログラミング初心者以前

「関数」をはじめから丁寧に

「関数というのはかなり問題のある訳語です」と何かの本で見かけました。どの本だったのか失念してしまいましたが、プログラミングにおいては私も同じように感じます。

現在の世界では「関数とは何か」ということを理解するのは大変重要ですが、これを初心者にちゃんと解りやすく書かれた文章がほとんど有りません1。これは初心者以前の用語であって、初心者向けの書籍であってもすでに知っている前提です。

関数なら学校で習った?

関数という言葉は中学校の数学でも登場します。しかしながらコンピュータで言うところの関数は、中学数学で習う関数の概念とはかなり異なり、また高校数学以降で習う関数の概念とも若干異なるため、ちゃんと説明を受けて理解しておかないと、続く学習に支障が出ます。いわゆる「つまづき」になってしまいます。

そもそもプログラミングは小学生から学ぶことになりそうです。中学数学を学ぶまで待つわけにはいきません。小学生のうちはカリキュラムの中にまだ関数の概念を持ち込まないのだとしても、覚えの早い子は自分で手を伸ばしてどんどん学んでいきます。そうした時に応えられる情報が必要です。

この記事は小学生に向けて、あるいは、プログラミングを学ぶ小学生に応える立場にいる大人に向けて書いたものです。また、数学における関数について説明したものではありません。

関数のもとの言葉

最初に書いた通り、関数とはなにかを解りにくくしている原因の一つに「関数」という訳語の印象が大きくかかわっているのではないかと思われます。

「関数」の原語は「function」です。

カタカナで書くと「ファンクション」ですね。この言葉を手元の英和辞典で引いてみると関数のほかに、「機能、働き;任務;職務;儀式」などの訳語があります。日本語では「関数」の他に「機能」として訳されることも多い言葉です。

「ファンクション」と聞いて何か思い出される方もいらっしゃるのではないでしょうか。キーボードの上の方に「ファンクション・キー」なるものが並んでいますね。[ F1 ] とか [ F2 ] とかいうやつです。キーボードによっては付いていないものもあります。このキーは押すとただ文字を表示するのではなく、画面の明るさを調整したり、音量を調整したり、なにかの特別な「機能」を持ったキーです。ということで「機能(ファンクション)キー」と呼ばれています。

プログラムにおける「Function(関数)」も、それを呼び出すことによって何かの処理を行ったり、引き渡した数値を計算したりという「機能」をもっています。これらのことから関数とは「機能」という言葉とも密接なつながりが有るらしいことがわかります。

数に関係している?

「関数」という文字を見ると、何か「数」に関係している様な気がしますがどうなのでしょうか。

では実際の関数をここで見てみましょう。

最初のサンプルとして採用するのは PHP です。人気プログラミング言語ランキングで不動の4位を保つ2柔軟性の高い言語です。微妙なランクですが関数を定義する際に「function」キーワードを使うことと「print(印刷という意味ですが、プログラミングの世界では『表示』の意味で使われることも多い)」が使えるなど今回の説明には適しています。

説明のためだけですので、できるだけシンプルにしてみます。

<?php
function foo() {
    print 'こんにちは';
}

と言いながら、このサンプルには数字が全く出てきません。イメージと違います。やはりプログラミング言語においては「機能」と訳すべきだったのではないかと感じてしまいますね。

コードの説明をします。最初のでキーワード「function」が出てきます。これから関数の定義が始まりますよ、という意味です。その次に関数の名前である「foo」があります。このような形で関数を定義する言語は他に JavaScript などがあります。JavaScript の定義も見てみましょう。多くのプログラミング言語の書き方を見比べてみることで「関数とはなにか」というイメージがよりつかみやすいと思います。

/* JavaScript */
function foo() {
    console.debug('こんにちは');
}

似ているところがありますね。3行目が違うだけですね。どちらのサンプルも3行目は「'こんにちは'という文字を表示せよ」という意味です。JavaScript の方は「コンソールにデバッグ出力してね」という意味で、出力先を指定しています。この「関数」は、そうした「機能」を持っています。

まだまだ疑問に思うことは多いです。

  • foo のうしろにある空の括弧はどういう意味?
  • さらにその後ろにある巻き括弧はどういう意味?
  • 文字を表示するだけで書き方が違うのはなぜ?

また気の早い人は「実行してみたけど何も表示されない」と思うかもしれません。一つずつ説明します。

行末にある「;(セミコロン)」は一つの処理の区切りを表しています。これによって行を複数行にわけることが簡単になります。プログラミング言語によっては不要ですが、逆に長くなってしまった行を分割したい時に不便になることが多いです。

仮引数(かりひきすう)

プログラミング言語における関数とは、よく使う共通の処理を、再利用しやすいようにまとめたもの」という説明を聞いたことがあるでしょうか。そのとおり関数は再利用しやすいように一連の処理まとめる手法の一つです。

手法の一つと言いました。関数の他に「クラス」「メソッド」「サブルーチン」「プロシージャ」「トレイト」「モジュール」「マクロ」など様々な「処理をまとめる」手法があります。最初から全部覚える必要はありませんし、全部使うわけでもありません。いつか学ぶ際も「関数の親戚」くらいに思って構いません。関数は機能と同じ言葉なのですから。また、もしこれらの概念を既に知っていたら「親戚のような仕組み」と考えて構いませんので「異なる部分はなにか」を考えてください。

しかし再利用するならばもっと汎用的(もっといろいろ使えるもの)にしたいものです。最初のサンプルは「こんにちは」としか表示できませんから、もっと他の表示もできるように改造してみましょう。

foo のうしろの括弧は、関数が値を受け取るための「入り口」です。最初のサンプルは括弧の中身が空なので、関数がなにも値を受け取らないことを示しています3。「こんにちは」の部分を変数にして、いろいろな文字が表示できるようにしてみましょう。

<?php
function foo($greeting) {
    print $greeting;
}

最初のサンプルの「こんにちは」の部分が変数 $greeting(あいさつ)になりました(PHP では、変数の頭に $ 記号があります)。

この $greeting の部分は引数(ひきすう)というものです。パラメータともいいますが、こちらの方が解りやすいでしょうか。関数定義に書かれている方の引数は仮引数とも呼ばれます。「もし仮に○○という値がこの関数に渡されたら」という感じで覚えておけばいいでしょうか。

ここまで「数」で終わる言葉がたくさん出てきました。「関数」の他に「変数」「引数」と。が、やっぱり数字はありません。変数や引数にはもちろん「数」を入れることもできますが、コンピュータの世界で「数」というと数に限らず「なんらかのデータ」と同じような意味で使われることがあります。変数や引数も同様です。

関数の呼び出し

「実行してみたけど何も表示されない」についてですが、最初のコードはその「再利用したい部分」としての関数を「定義」しただけで呼び出していないためです。呼び出しを含めて書いてみます。

<?php
function foo($greeting) {
    print $greeting;
}
foo('こんにちは');

最後の行が関数の呼び出しです。

まだ動かない

関数の呼び出しを追記したのにまだ動かないとお嘆きでしょうか。PHP のフルバージョンを書いておきます。

<?php
function foo($greeting) {
    print $greeting;
}
foo('こんにちは');

最初の行は「ここから PHP のコードがはじまりますよ」という意味です。「終わりは?」と思うかもしれませんが「書かなくても良い」ことになっていて、やがて「書かない方がいい」になりました。

JavaScript を使ってブラウザだけで動かしたい場合、コンソールの入力欄に下記のプログラムを改行なしで入力することで実行できます。

/* JavaScript */
function foo(greeting) {
    console.debug(greeting);
}
foo('こんにちは');

以降のサンプルをブラウザのコンソールで試してみたい場合は print を console.debug() に替えることと、改行を取り除くことで対応できます。$ 記号はあってもなくても構いません。

巻き括弧は関数の定義の範囲を表す

最後の行は関数の定義に含まれません。巻き括弧「{」は関数の中身(処理内容)が始まることを示し、「}」は関数の中身が終わることを示しています。

この「関数の定義の範囲」を示す方法はプログラミング言語によって違う場合があります。サンプルの PHPJavaScript は同じでした。C言語(系)、Java なんかも同じです。Python はインデントでブロックを表現します。VBVisual BASIC)系は `End Function' で関数の終わりを表します。

実引数(じつひきすう)

関数の呼び出し側には、$greeting に入ってほしい値の「こんにちは」が書かれています。これも引数で、実引数と呼びます。「実際に渡す値」だから実引数と覚えておけばいいかと思います。

仮引数も実引数もエンジニア間の日常会話では単に「引数」と言っています。どうしても区別したいときだけ「仮引数」「実引数」という言い方をします。

処理の結果を返す

関数は処理した結果を返すことができます。最初からサンプルを示します。

<?php
function sum($a, $b) {
    return $a + $b;
}
print sum(1, 2);

サンプルとして初めて数字が含まれています。お察しのとおり、プログラム全体は「1と2を足した結果を表示する」というだけのものです。別に楽しいことは何も無いプログラムですが、関数の説明には適した単純さです。

関数の中身に「return(リターン。戻すこと。報酬・利益などの意味)」とあります。これにより関数はその呼び出し元になんらかの値を返すことができます。

関数の名前 sum ですが、これは英語の「summary(まとめたもの。概要。合計などの意味)」に由来します。

では先ほどの「foo」は何に由来しているのでしょうか?実は特に意味がありません。しかしこの「特に意味がない」ということを確実に示したい場合があります。今回のように意味の有る言葉「function」を引き立てるために、他の部分をぼかしたり抽象化したりするためです。そのような場合に意味が無い言葉をわざと使うことがあります。こうした場合に使われる言葉は「foo」「bar」「baz」「hoge」「fuga」などがあります。いずれ様々なサンプルで広く目にすることになると思います。

表計算ソフトの関数

sum というと表計算ソフトで頻繁に使われる関数として有名なものです。例えば「=SUM(A1:A10)」という使い方をします。これはどういう意味でしょうか。

数式と考えると「=(等号)」の左側に何もありませんので、へんな感じがします。実はこの左側には「このセルの値は...」という意味が暗黙的に含まれています。この式「=SUM(A1:A10)」全体で「このセルの値は、セルA1からA10までの範囲の合計とする」という意味になります。

数に関係してきた

先ほどのサンプルをもう一度見てみましょう。

<?php
function sum($a, $b) {
    return $a + $b;
}

この関数は表計算ソフトの SUM ほどの便利さはありませんが「与えられた引数の二つを合計して呼び出し元に返す」という「機能」を持っています。次のサンプルを見てください。

<?php
function sum($a, $b) {
    return $a + $b;
}
$c = sum(1, 2) + sum(3, 4);

関数の結果(この場合は合計値)を、さらに計算して変数 $c に代入しています。

このようにプログラミングにおいての関数も、数学における関数も、数式に組み込むことができます。表計算ソフトの関数もチラと説明しましたが、こちらは値を返してくれるものが多いので、関数の戻り値をまた別の関数に渡すなど複雑な数式を作り上げることができます。

まとめ

コンピュータの世界の関数も数学の世界の関数も似ているところが出てきました。

  • よく使う処理群(計算式群)をまとめている
  • 引数をとることができる
  • 処理結果(計算結果)値を返すことができる

このような形で抽象化できる概念かと思います。

このように見てみると結構「数」に関係しているな、と思えてきます。冒頭に「問題のある訳語」と申しましたが「全く的外れな訳語」ではないことが解ります。

「関数」と「機能」は英語の function に該当することを考えると、その理解に役立ちます。しかしやはり「関数」と「機能」は違う概念なので、違う名前を持っていることが役立ちます。矛盾しているようでしていない、複雑な感情が芽生えてきます。

コンピュータの世界では、かつて入力できる記号が限られていたことと「行」に縛られることから、数学とは異なる表現方法をとらざるを得ません。そして利便性や要求から、あえて異なる表現方法を用いていることもあります。関数もおなじく、ずいぶんと異なる表現が多いですが、概念として理解することはとても重要です。願わくばこの記事がその一助になれば幸いに思います。

小学生からはじめるわくわくプログラミング

小学生からはじめるわくわくプログラミング


  1. ある本では「関数とは自動販売機のようなものです。お金の変わりに数値を渡すと商品の変わりに返り値を得ることができます。また使う人が中身がどうなっているか気にする必要がないためです」といった様なことが書いてありました。この説明で解りますか?わたしはかえって混乱しただけでした。「自動販売機だって?お金は何処にいれるの?商品は何処に出てくるの?おつりは?返金するときは?」「プログラマは中身を気にしなくて良い『使う人』ではなく、その『中身を作る人』なんじゃないの?」。エンジニアになってずいぶん経つ今考えても噴飯もののたとえです。ありえません。プログラミングを現実世界にたとえるのは逆効果です。理解を妨げる効果しかもたらしません。いくつかの特徴が似ているからといって概念が似ているわけではないからです。そのような本は読んではいけません。そのような本は、書いている人間が「このたとえは全くピッタリだ!オレってうまいこと言ったな」などと自分に酔っているだけで、読者を置いてきぼりにしています。そのような本はオブジェクト指向プログラミングについて書かれた本に、とくに多く見受けられます。

  2. WIRED.jp から。2018年前半現在、Qiita のタグランキングの中でも、フレームワークなどを除いて言語に限ってみると4位であることが多いです。何かジワジワきます。

  3. 関数が引数を受け取らない場合、最初の括弧は省略できてもいいのではないかと思うかもしれませんが省略できない言語が多いです。プログラミングの世界では「何も受け取らない」「何も返さない」など、「何もない」ことを明示できる方が「分りやすい」という理由で好まれる傾向があります。