関数の定義と呼び出し
R における関数は、数値や文字列と同じく 1 つの値です。function キーワードで作り、変数 に何かを格納するのと同じように <- で名前に結び付けます。
各部分を見ましょう。function(x) は x という 1 つの引数を宣言し、波括弧が本体を保持し、square(4) を呼ぶと x を 4 にして本体が実行されます。本体が 1 行なら波括弧は省略できます — square <- function(x) x^2 は同じ関数です — が、本体が育ってくると波括弧の方が読みやすくなります。
関数は単なる値なので、変数について知っていることがすべて当てはまります。再代入したり、別の関数に渡したり、リストに格納したりできます。この 1 つの事実が、apply ファミリー を含む慣用的な R の半分を支えています。
戻り値: 最後の式が勝つ
R の関数は、最後に評価した式が生み出したものを返します。必須の return 文はありません。
return() は確かに存在し、期待どおりに動きます — その場で関数を止め、引数を返します。慣用的な R はこれを 早期脱出 のために取っておきます。入力のせいで残りの作業が無意味になるとき、先頭で抜けるのです。if-else によるチェックと組み合わせましょう。
最終行に return(a / b) と書いても間違いではありませんが、単なるノイズです。return() は早く起こる脱出のために取っておき、通常の経路は最後の式に語らせましょう。
既定値と名前付き引数
引数は既定値を持つことができ、引数リストの中で = を使って宣言します。既定値で満足している呼び出し側は、単にその引数を省略します。
3 番目の呼び出しはもう半分の話を示しています — 名前付き引数 です。呼び出し側で name = "Ada" と書くと、位置は関係なくなります。R はまず名前で照合し、残りの引数を位置で埋めます。ここから実用的な規則が 2 つ導かれます。
- 必須の引数を先に、既定値を持つ引数を後に置きましょう。そうすれば位置指定の呼び出しが自然に保たれます。
- 呼び出し側では、位置から自明でない引数には名前を付けましょう。
greet("Ada", punctuation = "?")は、読み手にカンマを数えさせるより明快です。
... による引数の受け渡し
特殊な引数 ...(「ドット」と読みます)は「任意個の追加引数」を意味します。... を宣言した関数は、列挙していない引数も受け取り、それを別の関数へ転送できます。
shout() は単語をいくつ渡されたかを知りませんし、気にもしません — すべて paste() に渡すだけです。punctuation がドットの 後ろ にあることに注目してください。... の後に宣言された引数は名前でしか設定できず、これはオプションにとってまさに望ましい性質です。この受け渡しパターンは base R のいたるところにあります — sapply(x, round, digits = 2) が動くのは、sapply が自身の ... を通じて digits = 2 を round に転送するからです。
ドットの代償は、打ち間違いが静かに通り抜けてしまうことです。punctuation を punctation と綴り間違えると、エラーを出す代わりに ... に飲み込まれるだけです。ドットを使う関数は小さく保ちましょう。
無名関数
関数が一度しか必要ないとき — 典型的には別の関数の引数として — 名前を付けること自体を省略できます。
どちらの行も同じことをします。function(x) x^2 が古典的な書き方で、\(x) x^2 は R 4.1 で追加された短縮記法です。ここで \ が function という語の代わりを務めます。キー入力数以外はあらゆる点で同一であり、短縮記法は別種の関数ではありません。
無名関数は、操作が 1 行で済み、1 か所の呼び出しに結び付いているときに使いましょう。同じラムダを 2 か所に貼り付けた瞬間、あるいは 1 行を超えた瞬間に、名前を付けてください。名前付きの関数はテスト可能で、それ自体がドキュメントになります。
スコープ: 関数から何が見えるか
R は レキシカルスコープ を使います。関数が必要とする変数を、自身の引数やローカルな代入の中に見つけられないとき、関数が定義された 環境を探します — 呼び出された場所ではありません。実際上これは、関数が周囲のスクリプトの変数を読めることを意味します。
その裏返しとして、関数の内部での代入は 決して外に漏れません。change_inside の内部の rate <- 0.5 は、関数が戻ると消える新しいローカル変数を作ります。外側の rate は依然として 0.1 を表示します。これは機能です — 関数が誤ってワークスペースを踏み荒らすことはありません — が、内側の代入が残ると期待する初心者を驚かせます。関数が結果を外の世界へ渡す必要があるなら、それを返して呼び出し側で代入しましょう。(外側に手を伸ばす <<- 演算子もありますが、本当に必要になるまではコードの臭いとして扱ってください。)
実践例
これが報われるパターンです。3 行の分析を繰り返している自分に気づいたら、関数に包んで再利用しましょう。測定値の ベクトル をいつも要約しているとします。
このページの内容がすべて詰まっています。既定値を持つ digits 引数、それを上書きする名前付きの呼び出し、そして戻り値を担う最後の式(round(out, digits))。この関数は文のように読め、任意の数値ベクトルで動き、中央値を追加しようと決めたときには 1 か所だけを直せば済みます。
この記事のまとめ
name <- function(args) { body }で関数を作ります。最後に評価された式が戻り値です。return()は早期脱出のためのもので、通常の最終行のためではありません。- 既定値は引数リストの中で
=を使って宣言します。名前付き引数は呼び出し側を順序に依存させず、読みやすくします。 ...は任意の追加引数を受け取って転送します — 強力ですが、打ち間違いを隠します。function(x)と\(x)は同じものです。1 回限りの 1 行処理には無名関数を使いましょう。- 関数は定義された場所から変数を読みます。関数内部の代入は内部に留まります。
次は apply ファミリー — あなたの 関数を受け取り、ベクトルやリスト全体に適用する関数群です。
よくある質問
R で関数を作るにはどうすればよいですか?
function オブジェクトを名前に代入します: square <- function(x) { x^2 }。丸括弧に引数、波括弧に本体を書き、square(4) のように呼び出します。最後に評価された式が関数の戻り値になります。
R で return() は必要ですか?
いいえ。R の関数は最後に評価した式の値を自動的に返します。return() は存在しますが、慣用的な R ではそれを早期脱出のために取っておきます — 入力が不正なときや、端のケースを処理したときに関数の先頭で抜けるためです。
R の無名関数とは何ですか?
名前を付けずに定義する関数で、通常は別の関数にそのまま渡します: sapply(x, function(v) v^2)。R 4.1 以降には短縮記法 \(v) v^2 もあり、より少ないキー入力でまったく同じ意味になります。