プログラミング入門 Part 4
これはプログラミング入門講座シリーズの最終講義です。これを無事に修了した読者は称賛に値します。この講義では関数についてもう少し深く説明します。第一講義の内容を覚えていれば、関数とは名前でラベル付けがされたコードのブロックでありプログラムのどこからでも呼び出せるものであるとわかると思います。変数と配列と同じように、関数では数値や文字列を扱えます。これまでも、この入門講座シリーズで何度も VAL と INPUT$ 関数を先行して使ってきました。これまでに読者は関数の基本概念に関してかなり自信があると思います。さて、短めの概要で INPUT$ と VAL 関数について復習しましょう。
INPUT$ 関数は単体引数を受け取る文字列関数です。ユーザが入力する前にプロンプトが表示されます。こちらは基本構造です:
Input$ ( prompt$ ) - prompt$ はユーザが視認できるプロンプトです。実行完了後に関数は値を返します。INPUT$ において、この関数はユーザが入力したものを返します。基本的に関数の返値は入力したものと等しいです。したがって変数を使える多くの場所で関数を使えます。この説明については、以下の用例を参照してください。
A = Abs(-4)
B = Sqrt(25)
C = A + B
Print C
上述の用例において一行目は ABS 関数で -4 の絶対値を取得しています。つまり、 ABS 関数は -4 の絶対値を返します。その後、 ABS(-4) の返値である整数 4 を変数 A へ代入します。25 の平方根を求めるために次行で SQRT 関数を使います。SQRT(25) は 25 の平方根である 5 を返した後に返値を B へ代入します。次に A の値と B の値を加算して変数 C へ代入します。そして最後の行で C の値をコンソールへ出力します。RCBasic の全関数も含め先の関数における詳細はリファレンスマニュアルを参照してください。さて、この用例の処理内容理についてはっきりわかっているので、より短く記述できるか試してみます。以下の用例を参照してください。
C = Abs(-4) + Sqrt(25)
Print C
関数で返された値を加算した後に C へ代入することで以前の行から二行ほど削りました。 ABS と SQRT ともに数値の関数であるため、数値や変数と全く同じように算術処理で使えます。冗長だと思うのでしたら、このように一行でまとめて短く記述できます。
Print Abs(-4) + Sqrt(25)
最初は 4 行あったコードを ABS と SQRT 関数の返値を加算してコンソールへ出力するよう変更することで 1 行へまとめました。常時、変数や配列へ値を保持しておきたいのはわかりますが、その必要がないことを知っておくのは都合が良いと思います。
これまでのところ第一入門講座にて、その大半を解説しました。RCBasic にはユーザ入力の取得、現在時刻の取得、ファイルを開く、などの様々な課題を処理するための豊富な組み込み関数があります。将来、これ以外の関数を一歩進んだ入門講座で解説することを検討していますが、リファレンスマニュアルで関数全体の用法を参照できます。ですが、ここでは自作関数の作成方法を解説します。
プログラムで自作関数を作成できるようになると非常に便利です。大量のコードの書き直しを防ぐだけでなくエラー確認にも効果的、かつコードのデバッグがしやすくなります。これを説明する前に課題を解いてみましょう。
これは入門講座 2 の課題の完成版コードです。ユーザが 5 個の数値を得た後に、それらの平均値を出力するプログラムを書くよう出したものです。
Dim numbers[5]
user_input$ = ""
Print "番号を 5 回入力してください"
For index = 0 To 4
user_input$ = Input$("番号を入力してください" + Str$(index+1) + ": ")
numbers[index] = Val(user_input$)
Next
average = (numbers[0] + numbers[1] + numbers[2] + numbers[3] + numbers[4]) / 5
Print "平均値は " + average
少しの時間でいいので各行を読み通した後に、各行の動作に関して理解できるか確認してください。少し忘れている場合は、このコードの解説があるプログラミング入門 第三部の冒頭を参照してください。このプログラムは 5 の平均値を返す関数の作成後に変数 AVERAGE の内容を置換します。
自作関数を使うには FUNCTION キーワードで関数を始めます。その後、 END FUNCTION の行で関数を閉じます。以下を参照してください。
Function MyFunc ( arg1, arg2, arg3, ... )
...実行可能コード
Return (返値)
End Function
備考として、必要であれば少量、または大量の引数を関数で扱えます。そして、重要なことを言いますが、関数名は変数名や配列名と全く扱いです。したがって RCBasic の組み込み関数名やキーワードと同じ名前は指定できません。さて、 AVERAGE 関数を作成してみましょう。
Function Average( num1, num2, num3, num4, num5 )
a = (num1 + num2 + num3 + num4 + num5) / 5
Return a
End Function
上述の一行目は 5 個の引数を扱う AVERAGE 関数を作成します。これらの数値は変数 num1, num2, num3, num4, および num5 へ代入します。二行は数値から平均値を求めて変数 A へ結果を代入します。三行目は関数全体で求めた A の値を変数 A として返します。そして、最後の行は関数の終端であると RCBasic へ指示します。
この関数を使うには ABS や VAL 関数と同じ様に呼び出します。
Average(5,10,15,20,25)
自作関数は数値を扱う関係で数値を代入したり、それ以外の数値と併用して算術処理を行えます。
x = Average(2,5,8,3,5)
プログラムで関数を使うには使用前に関数を作成してあるか確認してください。結局のところ、作成前に使うことは可能です。つまり、プログラムの開始時点で自作関数を作成します。
Function Average( num1, num2, num3, num4, num5 )
a = (num1 + num2 + num3 + num4 + num5) / 5
Return a
End Function
Dim numbers[5]
user_input$ = ""
Print "番号を 5 回入力してください"
For index = 0 To 4
user_input$ = Input$("数値を入力してください" + Str$(index+1) + ": ")
numbers[index] = Val(user_input$)
Next
'こちらは AVERAGE 関数で使います。
'---------------------------------------------------------
Print "平均値は "; Average(numbers[0], numbers[1], numbers[2], numbers[3], numbers[4])
このプログラム最終行で平均値を得るために PRINT ステートメントで AVERAGE 関数を使います。これまで数値の関数だけを作成していました。文字列の関数では文字列の変数と配列と同様に関数作成時に名前の末尾へ $ を追加する以外は数値のときと同じです。また、文字列の関数を作成するときは数値ではなく文字列を返していることを必ず確認してください。この単純な文字列関数の用例をご確認ください。
Function MyStringFunction$ ()
Return "HELLO WORLD"
End Function
Print MyStringFunction()
先へ進む前に、このコードを編集して別の関数を作る時間確保していただくことを望みます。
時に、関数で何も返す必要が無いときがあります。この関数の用例をご確認ください。
Function Count_To_10()
For i = 1 To 10
Print i
Next
Return 0
End Function
Count_To_10()
上述の関数は 1 ~ 10 までの数値をコンソールへ出力します。とりあえず何かを返す関係で 0 を返します。しかし、この関数の返値は一切不要です。この場合のように関数で何も返す必要が無なければ代わりにサブルーチンを作成できます。SUB ルーチンはなにも返さない以外は関数と同じようなものです。サブルーチンは返値を返しませんので、数値や文字列のように使ったり変数へ代入できません。SUB キーワードを使う以外は関数と同じです。こちらはサブルーチンの構造です。
Sub MySub ( arg1, arg2, ... )
...実行可能コード
End Sub
サブルーチンは変数への代入や算術処理ができないことを除き関数と呼び出し方法は同じです。こちらは以前にサブルーチンとして作成した COUNT_TO_10 関数です。
Sub Count_To_10()
For i = 1 To 10
Print i
Next
End Sub
Count_To_10()
これまでの関数とサブルーチンでは引数の値渡しを説明してきました。値渡しとは、関数の引数として変数が渡されたときに、関数は変数に代入された値を使うものの、変数本体の値は変更しないことを意味します。実例として、この用例を確認してください。
Sub CoolBeans ( n )
n = 5
End Sub
MyVar = 20
CoolBeans ( MyVar )
Print "MyVar = "; MyVar
サブルーチン COOLBEANS の引数 N へ MYVAR を渡すと COOLBEANS の引数 N には 5 が代入されるため、 MYVAR の結果は 20 のままとなります。これは COOLBEANS サブルーチンに渡すときに MYVAR が値渡し (BY VALUE) になるからです。関数、またはサブルーチンへ変数を渡す方法を変えるには、参照渡し (BY REFERENCE) の引数を扱えるようにします。サブルーチンや関数で引数を参照渡しとして扱うには、関数やサブルーチンの定義において引数名の直前に BYREF キーワードを指定します。さて、こちらは以前の用例において引数を参照渡しで扱う方法です。
'注意点として引数名の直前に BYREF を用いています。
Sub CoolBeans ( ByRef n )
n = 5
End Sub
MyVar = 20
CoolBeans ( MyVar )
Print "MyVar = "; MyVar
さて、 COOLBEANS へ MYVAR を渡すとき、 COOLBEANS はサブルーチンの内側で引数値を変更します。つまり、渡された引数を用いて変数の値を変更します。したがって MYVAR の出力をすると結果は 5 になります。
この入門講座で最後に扱うのはスコープです。スコープはプログラムで変数にアクセスできる場所を意味します。この用例を確認してください。
Sub Test()
A = 5
End Sub
Print A
この上述のコードを実行するとコンパイルエラーになります。このコンパイルエラーが起きたのは A が存在しないときにコンソールへ変数 A の値を出力しようしたからです。しかし、 PRINT A を呼び出す前にサブルーチン TEST の内側で変数を A を作成したにも関わらずこのエラーが起きたのでしょうか?変数 A はサブルーチンの内側で作成したものであり、それ以外はプログラムのスコープではサブルーチンの外側になるからです。関数、サブルーチン、あるいはループで作成した変数は外側からアクセスできません。変数 A は TEST の内側に作成するため参照可能範囲は TEST の内側に制限されます。ですが、 TEST の作成前に変数 A を作成した場合は、 A の作成後はプログラム全体での同じ扱いとなり、 TEST の内側にある A へアクセス可能になります。この用例を参照してください。
A = 55
Sub Test()
Print "Test は "; + A+5
End Sub
Print "A は "; A
Test()
さて、このプログラムでは A の値を出力するだけにとどまりません。作成したサブルーチンでも変数 A を使用できます。また、サブルーチンの内側でも変数 A を変更可能です。この用例を確認してください。
A = 55
Sub Test()
A = A + 1
End Sub
Print "A は "; A
Test()
Print "A は "; A
上述のコードは最初に 55 を出力します。その後、 Test が呼び出されたときに A (値は 55) に 1 を足した値が A へ代入されます。したがって最終行の出力として A は 56 となります。
この入門講座では読者全員が今すぐ容易に完全理解できるとは考えていない前提で多数の情報を扱いました。筆者は読者が考えうるもので自作関数の作成などありとあらゆることをして大いに楽しまれること奨励します。また、時間があるときにリファレンスマニュアルの通読と組み込み関数を試してみてください。リファレンスマニュアルに記載のサブルーチンと関数の解説も併せてお読みください。
さて、以下の課題に挑んでみましょう。(リファレンスマニュアルを調べたとしても答えが見つからない場合は、課題を終えるために助けを求めることが必要になるかもしれません)
1. ユーザが乱数生成値を推測するテキストベースのゲームを書いてみましょう。
2. ユーザに単語の入力を求めるプログラムを書いてみましょう。単語に存在する母音数を返す関数を作成してみましょう。入力された単語に存在する母音数をユーザに報告する関数を使ってみましょう。