さっき決めたブログ

[Nim]Nimの文法を勉強 03 (プロシージャ(関数))

Nimの文法第3回目になります。
今回は関数についてに調べていきます。
Nimでは関数の事をプロシージャと呼ぶらしいので、今後そう呼ぶ事にします。

基本文法

プロシージャの基本文法は以下の通り
proc [プロシージャ名]([パラメータ]:[型], [パラメータ]:[型], ...):[戻り値の型] =

実行結果
りんごが5個あります。
10

プロシージャのネスト

プロシージャはプロシージャ内でネスト可能で、また、ブロック内でも定義することが出来ます。
その場合のスコープは変数と同じくプロシージャ、及びブロック内でのみ有効となります。

実行結果
myfunc
innerfunc
50
実行結果
0
2
4
6
8

前方宣言

プロシージャを呼び出す場合、呼び出す前にプロシージャの定義が記述されている必要があります。例えば、以下はエラーになります。

ただ実際には、再帰呼び出しなど定期の前にプロシージャを呼び出さなくてはならないケースというのもそんざいします。
その場合は、先頭にプロシージャの定義のみを先に記載しておくことでエラーを回避できます。

実行結果
200

パラメータについて

プロシージャに渡す引数の事をNimではパラメータと呼びます。
パラメータは通常は定数扱いなので、変更は不可なります。 例えば、以下のコードはコンパイルエラーになります。

但し、プロシージャ内でパラメータ変数を再定義することで、変更は可能です。

実行結果
50

パラメータの型にvarを付ける事で、参照型となり変更が可能になります。

実行結果
50
50

但し、その場合はパラメータとして定数を渡すことはできません。

パラメータの名前渡し

プロシージャを呼出す際のパラメータ指定方法として、今まで記載してきた様にプロシージャ内で定義された順番でパラメータを指定する方法(定義順)以外にも、パラメータ名を指定して受け渡す方法(名前指定)があります。

実行結果
りんごが5個あります。
10

定義順と名前指定は混在できるようだけど、明らかに見づらくなるので推奨はしていないようです。

パラメータのデフォルト指定

パラメータにはデフォルト値を指定して、呼び出し側でパラメータ指定を省略することも可能です。

実行結果
バナナが5個あります。
10
りんごが8個あります。
16

戻り値について

戻り値が不要な場合

Nimのプロシージャは戻り値の指定は必須になります。
また、プロシージャを呼び出す場合も戻り値の指定は必須となるため、以下のコードはエラーになります。

戻り値が不要な場合、呼出すプロシージャの手前に discard修飾子を指定すれば戻り値を省略することが可能です。

実行結果
val1 = 100

もしくは、プロシージャに {.discardable.} 修飾子を付けることで、そのプロシージャについては discard修飾子無しで省略可能になります。

実行結果
val1 = 100

result変数

戻り値はreturnで返しているが、暗黙の変数resultというのがあり、この変数に値を代入することで戻り値を返すことも出来ます。

実行結果
りんごが5個あります。
10

プロシージャのオーバーロードについて

Nimのプロシージャはオーバーロード可能です

実行結果
文字列 "バナナ" を引数とする myfunc
数値 10 を引数とする myfunc

曖昧な呼び出しの場合、コンパイルエラーになるそうです、こういうことかな?

カスタム演算子の定義

Nimではカスタム演算子を定義することが出来ます。
次の例は [文字列] - [数値] とすると、文字列の後ろから指定した数値分の文字を削除する演算子を定義しています。

実行結果
ABCD

イテレータ

イテレータとは

イテレータ(Iterators)とは for文とセットで使用する、プロシージャの様なものになります。
for文の説明for i in countup(0, 5): という表記が出てきましたが、この countup(0, 5) の部分が、0~5 の数値を "順番に" 返していくイテレータとなっています。
countup イテレータは組込のイテレータなので、実装を見る事は出来ませんが、こんな感じだと思ってください。

プロシージャとの違いは、定義の最初に記述する prociterator になっている部分と、結果を戻すのに、return ではなく、yield を使用している点になります。
yield は、return の様に値を戻してプロシージャを終了するのではなく、for文に値を返して、そのまま処理は続行されます。 つまり、yield が呼ばれた回数だけ、for文は処理を実行する事になります。

イテレータの例

自作のイテレータを作成する場合は、このような感じになります。

実行結果
赤いりんご
青いりんご
緑のりんご

プロシージャとイテレータの違い

イテレータはプロシージャと比べて次のような違いがあります。

  • イテレータは for ループの中でしか使用できません。
  • イテレータは returnステートメント、及び result変数を使用できません。 (逆に yieldステートメントはプロシージャの中では使用できません)
  • イテレータは再帰的な呼出はできません。
  • イテレータは前方宣言が出来ません。 (イテレータはコンパイル時にインライン展開されるからとの事。 ただし、将来的に出来るようになるらしい)

イテレータにはクロージャイテレータというものもあるそうなのだが、そちらについては改めて別に解説します。

参考にしたサイトなど

Nim Tutorial (Part I)
https://nim-lang.org/docs/tut1.html
Nim Tutorial Part Iを日本語訳してみた(前編)
https://qiita.com/KTakahiro1729/items/f4776f3a072c01f9086b
【Nim】個人的逆引きリファレンス
http://flat-leon.hatenablog.com/entry/nim_howto
DeepL翻訳
https://www.deepl.com/ja/translator

今回はここまで。

投稿者プロフィール

KARASU
うーん いろいろ考え中。。。

コメント

コメント取得中...

関連記事

TOPへ