今日の目標
今日は、同じ処理を何度も書かずに再利用するための proc を学ぶ。
Nimでは、処理をひとまとまりにして名前を付けるときに proc を使う。
まずは proc の基本形を理解し、次に値を受け取るための引数を使い、最後に計算結果を返す戻り値のある関数を書けるようになることを目標にする。
具体的には、名前を受け取って挨拶を表示する手続き、2つの数値を受け取って足し算する関数、半径から円の面積を計算して返す関数を作る。
今日の内容
7ー1 ~procとは何か~
プログラムを書いていると、同じような処理を何度も使いたくなる場面が出てくる。
たとえば、名前を表示する処理、合計を計算する処理、入力値を確認する処理などである。
これらを毎回最初から書くと、プログラムが長くなり、修正もしにくくなる。
そこで使うのが proc である。
proc は、処理に名前を付けて再利用できるようにする仕組みである。
日本語では「手続き」や「関数」と呼ばれることが多い。
厳密には、値を返さずに処理だけを行うものを手続き、計算結果などの値を返すものを関数と呼び分けることがある。
ただしNimでは、どちらも基本的には proc で定義する。
Nimで proc を書く基本形は次のようになる。
proc 名前() =
処理
proc の後に処理の名前を書き、その後ろに () を付ける。
そして = の次の行から、実行したい処理を書く。
Nimではインデントが重要である。proc の中に入る処理は、必ず字下げして書く必要がある。
インデントがずれると、Nimはどこまでが proc の中身なのか判断できなくなる。
よくあるミスは、proc を定義しただけで実行されると思ってしまうことである。
proc は、定義しただけでは動かない。
使いたい場所で 名前() のように呼び出して、初めて中の処理が実行される。
これは初心者がかなり詰まりやすい点である。
7ー2 ~引数とは何か~
proc は、ただ決まった処理を実行するだけでなく、外から値を受け取ることもできる。この外から受け取る値を「引数」と呼ぶ。
たとえば、毎回「こんにちは」と表示するだけなら、引数は必要ない。
しかし、「こんにちは、アリスさん」「こんにちは、ボブさん」のように、名前だけを変えて挨拶したい場合は、外から名前を受け取れるようにしたほうがよい。
このときに引数を使う。
Nimでは、引数を次のように書く。
proc greet(name: string) =
echo "こんにちは、" & name & "さん"
上の例では、greet という proc を定義している。
name: string は、「name という名前の引数を受け取り、その型は string である」という意味である。
Nimは型を重視する言語なので、引数には基本的に型を書く。
文字列を受け取るなら string、整数を受け取るなら int、小数を受け取るなら float を使う。
引数を使うと、同じ proc をいろいろな値で呼び出せる。
greet("アリス")
greet("ボブ")
このように書くと、同じ greet という処理を使いながら、表示される名前だけを変えられる。
よくあるミスは、文字列と数値をそのまま & でつなごうとすることである。
Nimの & は文字列同士をつなぐ演算子である。たとえば、"答えは" & 10 のように書くと、文字列と整数を直接つなごうとしているためエラーになる。
この場合は、$10 のように $ を使って数値を文字列に変換する必要がある。
7ー3 ~戻り値とは何か~
proc は、処理を実行するだけでなく、結果を呼び出し元に返すこともできる。
この返される値を「戻り値」と呼ぶ。
たとえば、2つの数を足し算する処理を作るとする。
画面に表示するだけなら echo で十分だが、計算した結果を別の計算に使いたい場合は、値を返す必要がある。
このようなときに戻り値を使う。
Nimで戻り値のある proc を書く基本形は次のようになる。
proc add(a: int, b: int): int =
return a + b
上の例では、add という proc を定義している。
(a: int, b: int) は、「a と b という名前の引数を受け取り、どちらも int 型である」という意味である。
: int は、「この proc は int 型の値を返す」という意味である。
return a + b は、「a と b を足し算した結果を返す」という意味である。
呼び出す側では、次のように戻り値を変数に入れられる。
let result = add(2, 3)
このように書くと、add(2, 3) の計算結果である 5 が result という変数に入る。
その後、result を使ってさらに計算したり、画面に表示したりできる。
よくあるミスは、戻り値の型を書いたのに return を書き忘れることである。
Nimでは最後の式が結果として扱われる書き方もあるが、初心者のうちは return を明示したほうが理解しやすい。
また、戻り値の型と実際に返す値の型が違うとエラーになる。たとえば : int と書いているのに "5" のような文字列を返すことはできない。
課題1
このドリルでは、名前を受け取って挨拶を表示する proc を完成させる。
greet という手続きを作り、引数として受け取った名前を使って「こんにちは、〇〇さん」と表示する。
穴埋め箇所には、proc の名前、引数の型、表示に使う変数名を入れる。
proc ____(name: ____ ) =
echo "こんにちは、" & ____ & "さん"
greet("ミドリ")
greet("ユウカ")
期待する出力は次のようになる。
こんにちは、ミドリさん
こんにちは、ユウカさん
まず、呼び出し側では greet("ミドリ") と書かれているので、proc の名前は greet にする必要がある。
次に、"ミドリ" や "ユウカ" は文字列なので、引数の型は string である。
最後に、受け取った値は name という引数名で使える。echo の中では、name をそのまま使えばよい。
課題2
このドリルでは、足し算をする関数を改造する。
出発コードでは、2つの整数を足して結果を返す add 関数がある。これを改造して、3つの整数を足せるようにする。
関数名は addThree とし、引数は a、b、c の3つにする。
出発コードは次のとおりである。
proc add(a: int, b: int): int =
return a + b
let result = add(10, 20)
echo "合計は " & $result & " です"
期待する出力は次のようになる。
合計は 60 です
改造後は、次のように呼び出せる形にする。
let result = addThree(10, 20, 30)
ヒントとしてまず、関数名を add から addThree に変える。
次に、引数を2つから3つに増やす。
Nimでは、proc addThree(a: int, b: int, c: int): int = のように、引数をカンマで区切って書く。
最後に、返す値を a + b ではなく a + b + c にする。戻り値の型は整数なので : int のままでよい。
課題3
この課題では、半径を入力として受け取り、円の面積を計算して返す関数を作る。
入力は radius という float 型の値である。処理では、3.14 * radius * radius を計算する。出力では、計算結果を画面に表示する。
関数名は circleArea とし、戻り値の型も float にする。
出発コードは次の通り。
proc circleArea(radius: float): float =
return ____
let radius = 5.0
let area = circleArea(radius)
echo "半径 " & $radius & " の円の面積は " & $area & " です"
期待する出力は次のようになる。
半径 5.0 の円の面積は 78.5 です
よくあるエラー例を確認する。
echo "面積は " & area
この書き方はエラーになる。
理由は、area が float 型の数値であり、文字列と直接 & で結合できないからである。
直すには、次のように "面積は " & $area と書いて文字列へ変換する。
もう一つのよくあるミスは、戻り値の型を int にしてしまうことである。
proc circleArea(radius: float): int =
return 3.14 * radius * radius
これは、float の計算結果を int として返そうとしているため型が合わない。
円の面積は小数になることが多いので、戻り値の型は float にするべきである。
今日のまとめ
今日は、処理を再利用するための proc を学んだ。
proc を使うと、同じ処理を何度も書かずに、名前を付けて呼び出せるようになる。
引数を使えば、外から値を受け取って処理を変えられる。
戻り値を使えば、計算結果を呼び出し元に返し、別の変数に入れて利用できる。
これらの機能を使いこなすことで、より複雑なプログラムを効率的に書けるようになる。
次回は、関数の中で変数のスコープやグローバル変数の扱いについて学ぶ。