Nim Tutorial Part Iを日本語訳してみた（前編）

#チュートリアルの訳の前に
Nimという言語は、python風の構文を持ち、C言語並みの速度を持つ、プログラミング言語です。
つまり、Pythonistaにとって夢のような言語です。

インストールは[こちら](http://nim-memo.hatenablog.com/entry/2016/10/24/173300)がわかりやすいと思います。
公式のインストールページは[こちら](https://nim-lang.org/download.html)からどうぞ。


Nimを勉強するにあたり、その日本語文書の少なさがボトルネックになると思い、手始めに公式チュートリアルを翻訳しました。[原文はこちらから](http://nim-lang.org/docs/tut1.html)これはその前半（パート1）の前編です。
もし、より適したアップロード場所や公式の翻訳フォームがあれば教えてください。

誤訳や誤解にお気づきの際は、遠慮なくお申し付けください。ツイッターにリプを飛ばすと反応は速いです。
サンプルコードは基本的に、[ideone](http://ideone.com/)で実行し、リンクを貼るつもりですが、ideoneのNimのバージョンが0.11.2（2016/12/29日現在）ですので、一部手元の実行環境で確認するにとどめています。


#Nimチュートリアル パート1 [Nim Tutorial (Part I)](http://nim-lang.org/docs/tut1.html)
著者:    Andreas Rumpf
バージョン:    0.15.2

##はじめに [Introduction](http://nim-lang.org/docs/tut1.html#introduction)

>*"Der Mensch ist doch ein Augentier -- schöne Dinge wünsch ich mir."*
「人間は視覚に頼る動物だ。私は美しい物が欲しい。」[^1]

[^1]: 恐らくRammsteinの[Morgenstern](http://herzeleid.com/en/lyrics/reise_reise/morgenstern)という歌からの引用。引用意図はぶっちゃけよく分からない。



これはプログラミング言語『Nim』のチュートリアルである。
変数・型・文などの、プログラミングの基本的な概念を理解した読者を想定したチュートリアルではあるものの、かなり基本的な事項のみ扱う。
より発展的な言語仕様の例は[マニュアル](http://nim-lang.org/docs/manual.html)に多く記載されている。
このチュートリアルや、他のNimの文書に記載されているNimのコード例は全て、[Nimスタイルガイド](http://nim-lang.org/docs/nep1.html)に従う。


##最初のプログラム [The first program](http://nim-lang.org/docs/tut1.html#the-first-program)

"hello world"に比べたら複雑なコードでNimの旅を始めよう。

[greetings.nim](http://ideone.com/sRVn62)

```nim:
# これはコメントである
echo "お名前は？ "
var name: string = readLine(stdin)
echo "やあ、", name, "!" 
```


このコードを"greetings.nim"に保存、コンパイル、実行してみよう。

```console
nim compile --run greetings.nim
```

`--run`[スイッチ](http://nim-lang.org/docs/nimc.html#command-line-switches)を付けると、コンパイルが終わるとファイルが自動的に実行される。

コマンドライン引数は、ファイル名の後に記述する事でプログラムに渡せる。

```console
nim compile --run greetings.nim arg1 arg2
```

よく使われるコマンドやスイッチは、省略形を持ち、以下のような記述も可能である。

```console
nim c -r greetings.nim
```

release版をコンパイルするには、以下のように記述すれば良い。

```console
nim c -d:release greetings.nim
```

デフォルト状態ではデバッグの為に、膨大な量のランタイムチェックを作る。[^2]
`-d:release`により、[これらのチェックは無効化され、最適化が行われる](http://nim-lang.org/docs/nimc.html#compile-time-symbols)。
[^2]: [原文](http://nim-lang.org/docs/tut1.html#the-first-program)では"generate runtime checks"である。runtime checkが良く分かっていないため、変な訳になっているかもしれない。

これが何のプログラムかは明白だろうが、構文の説明をしよう。
インデントのない文はプログラム実行時に実行される。
インデントにより、Nimは複数の文を一つにまとめる。
インデントはスペースのみであり、タブキーによるインデントは受け付けない。

文字列リテラルは二重引用符で囲む。
`var`文により、`name`という名前の`string`型（文字列型）変数を宣言できる。
この変数には[readLine](http://nim-lang.org/docs/system.html#readLine,File)プロシージャの返り値が代入されている。
このコードの場合、型の指定を宣言から省いてもよい。
というのも、コンパイラが「[readLine](http://nim-lang.org/docs/system.html#readLine,File)プロシージャが文字列型を返す事」を把握しているからである。（これはローカル型推論と呼ばれる。）
よって以下の記述も可能である。

[greetings1.nim](http://ideone.com/dzQmmt)

```nim
var name = readLine(stdin)
```




Nimにおける型推定が基本的に、このローカル型推定である事を覚えておいてほしい。これは簡潔さと可読性とが歩み寄った結果である。
`echo`・[readLine](http://nim-lang.org/docs/system.html#readLine,File)といった、コンパイラが既に把握している識別子がこの"hello world"コードには含まれている。
これらの組み込まれた識別子は、[システム](http://nim-lang.org/docs/system.html)モジュールで宣言されており、これは他の全てのモジュールが暗黙にインポートする。[^3]
[^3]: [原文](http://nim-lang.org/docs/tut1.html#the-first-program)では"the system module which is implicitly imported"とwhichの制限用法で記述されているが、リンクに飛ぶ限り、[システム](http://nim-lang.org/docs/system.html)モジュールは単一のモジュールであり、非制限用法的に訳している。ていうかこの著者、ちょいちょいコンマが足りない。


##字句要素（リテラルや識別子のこと） [Lexical elements](http://nim-lang.org/docs/tut1.html#lexical-elements)

Nimの字句要素を詳しく見てみよう。
他のプログラミング言語と同じくNimを構成する要素は、（文字列）リテラル、識別子、キーワード、コメント、演算子、その他記号である。

###文字列リテラル、文字リテラル[String and character literals](http://nim-lang.org/docs/tut1.html#lexical-elements-string-and-character-literals)

 文字列リテラルは二重引用符`"`で囲まれる。一方の文字リテラルは単引用符`'`で囲まれる。
特殊文字をエスケープするには`\`を用いる。例えば、`\n`は改行、`\t`はタブを意味する。
raw文字列リテラルもある。[^4]
[^4]: [原文](http://nim-lang.org/docs/tut1.html#lexical-elements-string-and-character-literals)では「バックスラッシュ」で書かれている。

[rawstring.nim](http://ideone.com/LguQwB)

```nim
r"C:\program files\nim"
```

raw文字列リテラル中の`\`はエスケープ文字ではない。

文字列リテラルを記述する最後の方法は、long文字列リテラルという第三の方法である。
long文字列リテラルは3つの二重引用符に挟まれる。`""" ... """`
複数行にわたって文字列を記述でき、`\`もエスケープ文字にならない。

使用例としては、HTMLコードを埋め込む、などがある。[^5]
[^5]: [原文](http://nim-lang.org/docs/tut1.html#lexical-elements-string-and-character-literals)では"HTML code templates"とあるが、templatesの指す意味が今一つ掴めなかった。まさかフレームワーク的な意味じゃあるまいし。

###コメント [Comments](http://nim-lang.org/docs/tut1.html#lexical-elements-comments)

文字列リテラル・文字リテラルの中でなければ、コメントは`#`で記述できる。
ドキュメント・コメントは`##`が先頭に付く。

[comments.nim](http://ideone.com/DBmazZ)

```nim
# コメント

var myVariable: int ## ドキュメントコメント
```

ドキュメント・コメントは特別な存在である。
ドキュメント・コメントは抽象構文木[^6]の中に含まれるため、`.nim`ファイル中[^7]の決まった場所にしか記述できないのだ。
これにより、シンプルなドキュメンテーション・ツールで事足りる。
[^6]: [原文](http://nim-lang.org/docs/tut1.html#lexical-elements-comments)では"syntax tree"とのみあるが、通常のコメントと比較した文脈であると考えて、「抽象」を補った。
[^7]: [原文](http://nim-lang.org/docs/tut1.html#lexical-elements-comments)では、"input file"とあるが、コメントの記述という文脈から、".nim"ファイルの事だと解釈した。Nimはメタプログラミングが売りであり、そういう意味の"imput file"を含んでいるのかもしれない。

[discard文](http://nim-lang.org/docs/tut1.html#discard-statement)[^8]とlong文字列リテラルを組み合わせて使うことで、ブロックコメントを書く、という方法もある。
[^8]: [原文](http://nim-lang.org/docs/tut1.html#lexical-elements-comments)通りのリンクを貼っているが、[こちら](http://nim-lang.org/docs/tut1.html#procedures-discard-statement)のほうが、適切に思える。

[discard_and_longstring.nim](http://ideone.com/8FrIVf)[^9]

```nim
discard """この中ならインデントの心配をすることなく
どんなコードもコメントアウトできる。
      yes("つまらない質問をしてもよろしいですか？")"""
```

[^9]: [原文](http://nim-lang.org/docs/tut1.html#lexical-elements-comments)でも`yes(""])`の記述がある。[マニュアル](http://nim-lang.org/docs/manual.html)を読む限り、このようなプロシージャは存在しないが、「ユーザーが定義したプロシージャ`yes()`」をコメントアウトした、という文脈と考えて、訳した。実際、[後で](http://nim-lang.org/docs/tut1.html#procedures)`yes()`というプロシージャが定義されている。

###数値 [Numbers](http://nim-lang.org/docs/tut1.html#lexical-elements-numbers)

数値リテラルの書き方は、他の多くの言語と同じである。
また、アンダーバー`_`を使って可読性を上げることもできる。（100万:`1_000_000`[^10]）
[^10]: [ideone](http://ideone.com/c7FMPn)と手元の実行環境で確認したが、`10_0000_0000`という日本風の表記も可能である。西洋かぶれの3桁区切りが嫌いな方は是非。
小数点`.`や`e`を含む数字は浮動小数点型になる。（10億:`1.0e9`）
16進数は`0x`、2進数は`0b`、8進数は`0o`がそれぞれ先頭に付く。先頭に`0`を付けたとしても、8進数には出来ない。

##var文 [The var statement](http://nim-lang.org/docs/tut1.html#the-var-statement)

var文を使うことで、ローカル変数やグローバル変数を新しく宣言できる。

[var.nim](http://ideone.com/tr6ain)

```nim
var x, y: int # xとyが``int``型であることの宣言
```

`var`文の後にインデントを入れると、ひとまとまりの変数を並べて宣言できる。

[var_at_once.nim](http://ideone.com/gthDnV)

```nim
var
  x, y: int
  # ここにコメントを入れることも可能である
  a, b, c: string
```

##代入文 [The assignment statement](http://nim-lang.org/docs/tut1.html#the-assignment-statement)
代入文を使うことで、新しく値を変数やメモリ領域に代入できる。

[assignment.nim](http://ideone.com/aVtz9y)

```nim
var x = "abc" #　新しい変数`x`を宣言し、値を代入する
x = "xyz"     # `x`に新たな値を代入する
```

`=`は代入演算子である。
現在、代入演算子をオーバーロード（拡張）・上書き・禁止することは出来ないが、今後のバージョンで変わりうる。
複数の変数をまとめて宣言する際、代入演算子を用いると、全ての変数に同じ値を代入できる。[^11]
[^11]: `var x, y = 1, 3`という表記（つまり、同時に宣言し、別々の変数を代入）は出来ないようである。[ideone](http://ideone.com/3vfEbW)でも手元の実行環境でも同じ`invalid indentation`と出てきた。正直、このエラーメッセージはバグレベルで分かりにくいと思うのだが…

[assign_at_once.nim](http://ideone.com/cA5O1M)

```nim
var x, y = 3  # 3を変数`x`と変数`y`に代入
echo "x ", x  # "x 3"を出力
echo "y ", y  # "y 3"を出力
x = 42        # `y`を維持しつつ、`x`を42にする。
echo "x ", x  # "x 42"を出力
echo "y ", y  # "y 3"を出力
```


複数の変数をまとめて宣言し代入するときに、プロシージャが呼び出されると、思わぬ動作をすることは覚えておいてほしい。[^12]
[^12]: [原文](http://nim-lang.org/docs/tut1.html#the-assignment-statement)では、修飾関係が入り組んでいる。"declaring multiple variables with a single assignment which calls a procedure"の"with a single assignment"は"declaring"に、"which calls a procedure"は"variables"にかかっていると考えているが、訳中ではそこをぼかしている。というのも、"calls a procedure"するのは、「変数」などではなく「値」であるように思えて仕方ないからである。呼ばれた回数を返すプロシージャとか。
コンパイルするときに、宣言・代入文は解きほぐされ、結果としてプロシージャを複数回呼び出すことになるからだ。
もし、返り値が副作用にプロシージャに左右される物であれば、変数に別の値が入ってしまうかもしれない。
まとめて代入する時は、この点に気を付けよう。[^13]
[^13]: [原文](http://nim-lang.org/docs/tut1.html#the-assignment-statement)では、"For safety use only constant values."という文であるが、"constant value"が厄介なため、まるっと意訳した。流石に後述の`const`で宣言される定数とは違うだろうし、「定数値」という訳が適切とも思えない。（定数と紛らわしいし）

##定数 [Constants](http://nim-lang.org/docs/tut1.html#constants)
定数は値と強く結びついた識別子[^14]である。
[^14]: [原文](http://nim-lang.org/docs/tut1.html#constants)では"symbol"となっている。シンボルの定義があいまいに思えるため、「識別子」とした。訳としては離れるが、意味としては遠くないはずだ。
定数の値は変えられない。
コンパイラは、コンパイルの間に定数宣言中の式を計算しておく必要がある。[^15]
[^15]: これはコンパイルの開発者に向けて書かれていると考える。というのも、Nimはいまだにver1.0に到達しておらず、（憶測ではあるが）コンパイル開発者もコミュニティに多くいるはずだからである。とはいえ、これが何を意味するかは明白である。例えば、.nim上では定数にプロシージャ経由で値を与えていても、.exe上ではその返り値がもう計算され、代入されているのである。さすコン。

　
[const.nim](http://ideone.com/jGCbzq)

```nim
const x = "abc" # 定数xは文字列"abc"を含む
```

`const`の後にインデントを入れると、ひとまとまりの定数を並べて定義できる。

[const_at_once.nim](http://ideone.com/M3WjA4)

```nim
const
  x = 1
  # ここにもコメントが書ける
  y = 2
  z = y + 5 # 計算が可能だ
```

##let文 [The let statement](http://nim-lang.org/docs/tut1.html#the-let-statement)
`let`文は`var`文のような働きを持つが、*単一代入*変数の宣言に用いられる。
つまり、初期化後、改めて値を代入できないのだ。

[let.nim](http://ideone.com/ETg5wz)（注:コンパイルエラーを吐きます）

```nim
let x = "abc" # 新たな変数`x`を宣言し、値と結びつける
x = "xyz"     # 不正な操作: `x`への代入
```

`let`文と`const`文の違いは以下のとおりである。
`let`とは再代入できない変数である。
`const`とは"コンパイル時に強制的に計算され、データ領域に代入しておく"

[const_readLine.nim](http://ideone.com/g8sWDg)（注：コンパイルエラーを吐きます）

```nim
const input = readLine(stdin) # エラー:定まった値を返す式が必要
```

[let_readLine.nim](http://ideone.com/o7zZRz)

```nim
let input = readLine(stdin)   # 実行できる
```


##制御文 [Control flow statements](http://nim-lang.org/docs/tut1.html#the-let-statement)
最初の"greetings.nim"プログラムは、全てが順番に実行される3つの文から構成される。
これで上手く作れるのは、簡単なアルゴリズムだけである。
要するに、分岐や繰り返しも必要だ。

###if文 [If statement](http://nim-lang.org/docs/tut1.html#control-flow-statements-if-statement)
if文はプログラムを分岐させる一つの方法である。

[greeings_if.nim](http://ideone.com/xQgu8k)（注:stdinに`""`を入力したい場合は、一回改行をしておかないと、runtimeエラーを吐きます）

```nim
let name = readLine(stdin)
if name == "":
  echo "憐れな。名を失ったのか？"
elif name == "名前":
  echo "面白いね、君の名前は名前なのかい。"
else:
  echo "やあ、", name, "!"
```

`if`文では0個以上の`elif`を入れる事ができ、`else`は任意である。
`elif`というキーワードは`else if`の略であり、過剰なインデントを回避するために使う。
（コード中の`""`は空の文字列を示す。文字を含まない）

###case文[^16] [Case statement](http://nim-lang.org/docs/tut1.html#control-flow-statements-case-statement)
[^16]: 元となった言語はよく分からないが、よくある`switch-case`に比べて英語の文法としては自然に見える。
プログラムを分岐させるもう一つの方法はcase文を使う。case文は複数に分岐できる。

[greetings_case.nim](http://ideone.com/vEUWUC)

```nim
let name = readLine(stdin)
case name
of "":
  echo "憐れな。名を失ったのか？"
of "name":
  echo "面白いね、君の名前は名前なのかい。"
of "デイブ", "フランク":
  echo "かっこいい名前じゃないか。"
else:
  echo "やあ、", name, "!"
```

見てわかる通り、`of`の後に、コンマ区切りで値を並べることも可能である。[^17]
[^17]: `break`がないのは、コンマ区切りが使えるからであろう。

case文は、整数型、他の順序型や文字列型を受けることが出来る。（順序型の説明は少し後にする）
整数型やほかの順序型に関しては、範囲指定も可能である。

[case_num.nim](http://ideone.com/Oi4JcM)

```nim
#真下のこの文は後で説明する
from strutils import parseInt

echo "数字を入力してください: "
let n = parseInt(readLine(stdin))
case n
of 0..2, 4..7: echo "入力した数字は以下の集合に属しています: {0, 1, 2, 4, 5, 6, 7}"
of 3, 8: echo "入力した数字は3か8です"
```

しかし実は上のコードはコンパイル出来ない。
それは、nが取りうるすべての値を網羅する必要があるのに、このコードでは`0..8`の範囲の値しか扱っていないからである。
「取りうる全ての整数を書く」事はあまり実用的でない（範囲指定の記法で可能ではあるが）。そのため、このコンパイルエラーを直すには、他の値に関しては特に実行することが無い事をコンパイラーに伝えるのがよい。

[case_num1.nim](http://ideone.com/rm1MSG)

```nim
...
case n
of 0..2, 4..7: echo "入力した数字は以下の集合に属しています: {0, 1, 2, 4, 5, 6, 7}"
of 3, 8: echo "入力した数字は3か8です"
else: discard
```

単独の[discard文](http://nim-lang.org/docs/tut1.html#modules)[^8]は*何も実行するな*文である。
elseの付いたcase文がエラーを持たない事をコンパイラは知っており、このエラーは消えるのである。
全ての文字列型を網羅することは不可能である事は覚えておいてほしい。というのも、網羅できない事が「case文を文字列で分岐するときは`else`が必要」な理由だからである。

一般的に、case文は部分範囲型や列挙型で使われる。これらの型の場合、取りうる値を尽くしたかのコンパイル時の確認が役に立つからである。


###while文 [While statement](http://nim-lang.org/docs/tut1.html#control-flow-statements-while-statement)
while文は簡単なループ構造である。

[ask_while.nim](http://ideone.com/6ifkxD)

```nim
echo "お名前は？ "
var name = readLine(stdin)
while name == "":
  echo "名前を教えてください "
  name = readLine(stdin)
  # 新しい変数を宣言している訳ではないため、ここに``var``はない
```

コード例では、ユーザーが何も入力しない場合（Returnばかり押す）、入力するまで名前を聞くためにwhileループを使っている。

###for文 [For statement](http://nim-lang.org/docs/tut1.html#control-flow-statements-for-statement)
`for`文は*イテレータ*から渡される要素をループ処理するための構造である。
コード例では、組み込みの[countup](http://nim-lang.org/docs/system.html#countup)イテレータを用いる。

[count_for.nim](http://ideone.com/aiTR7T)（注:コンパイルエラーを吐きます。[^18]　[こちら](http://ideone.com/WfrIBc)なら動きます）

```nim
echo "10まで数える: "
for i in countup(1, 10):
  echo $i
# --> 1 2 3 4 5 6 7 8 9 10 をそれぞれ別の行に出力する。
```

[^18]: ideoneのバージョンが古く(0.11.2)、何かと色々があると考えられる。インストールした環境(0.15.2)では問題なく動く。ideoneのコードでは`$i`を`()`で挟んだ。パッと見た限り動作、出力に違いはない。

組み込み演算子である`$`は整数型（`int`）や他のデータ型を文字列型に変換する。
変数`i`はforループにより暗黙に宣言されており、[countup](http://nim-lang.org/docs/system.html#countup)が`int`型を返すため、`i`も同じ型を持つ。
`i`は1,2,...,10と変わっていく。
それぞれの`i`の値は`echo`で出力される。
以下のコードも同じ操作をする。

[count_while.nim](http://ideone.com/3FgqTF)（注:コンパイルエラーを吐きます。[^18]　[こちら](http://ideone.com/IJyEpX)は動きます。）

```nim
echo "10まで数える: "
var i = 1
while i <= 10:
  echo $i
  inc(i) # iを1だけインクリメントする。
# --> 1 2 3 4 5 6 7 8 9 10 をそれぞれ別の行に出力する。
```

カウントダウンは同じくらい簡単にできる。（が、同じほどよく使われる訳ではない）

[countdown.nim](http://ideone.com/gcptGB)（注:コンパイルエラーを吐きます。[^18]　[こちら](http://ideone.com/bLuHFw)なら動きます）

```nim
echo "10から1にカウントダウンする: "
for i in countdown(10, 1):
  echo $i
# --> Outputs 10 9 8 7 6 5 4 3 2 1 on different lines
```

プログラムでカウントアップする事は、かなりよくある事であり、Nimは`..`という同じ動作をするイテレータを持つ。

[count_for_withdots.nim](http://ideone.com/Zmybs7)（注:コンパイルエラーを吐きます。[^18]　[こちら](http://ideone.com/Oj5VtB)なら動きます）

```nim
for i in 1..10:
  ...
```

###スコープとblock文 [Scopes and the block statement](http://nim-lang.org/docs/tut1.html#control-flow-statements-scopes-and-the-block-statement)
制御文について、まだ話していないことがある。
それは「新しいスコープを作る」ということだ。
この事は要するに、以下の例では`x`はループ外で取得できない、という意味だ。

[block_scope.nim](http://ideone.com/8IeTTL)（注:コンパイルエラーを吐きます）

```nim
while false:
  var x = "やあ"
echo x # 実行できない
```

while文やfor文は暗黙にブロックを作ります。
識別子は、それが宣言されたブロックからしか見えません。
`block`文は明示的にブロックを作るのに使われます。

[block.nim](http://ideone.com/qcP4CS)（注:コンパイルエラーを吐きます）

```nim
block myblock:
  var x = "hi"
echo x # こちらも動かない
```

ブロックの*ラベル*（コード例においては`myblock`）は任意である。

###break文 [Break statement](http://nim-lang.org/docs/tut1.html#control-flow-statements-break-statement)
`break`文を使うとブロックを途中で抜けることができる。
`break`文が抜けることができるブロックは`while`、`for`、`block`文によるブロックである。
`break`文により、最も内側のブロックを抜ける事が出来るが、抜けるブロックを*ラベル*で指定出来る。

[break.nim](http://ideone.com/wjaiYm)

```nim
block myblock:
  echo "ブロックに入る"
  while true:
    echo "ループの中"
    break # ループからは抜ける、ブロックからは抜けない
  echo "まだループの中"

block myblock2:
  echo "ブロックに入る"
  while true:
    echo "ループの中"
    break myblock2 # ブロックを抜ける（ループからも）
  echo "まだループの中"
```

###continue文 [Continue statement](http://nim-lang.org/docs/tut1.html#control-flow-statements-continue-statement)
他のプログラミング言語と同様、`continue`文により、直ちに次の反復処理に移る事が出来る。

[continue.nim](http://ideone.com/Vy0l7p) （注:runtimeエラーを吐きます[^19]）

```nim
while true:
  let x = readLine(stdin)
  if x == "": continue
  echo x
```

[^19]: これは手元の実行環境では問題なく動く。というのも、このコードは無限ループで繰り返し入力を求めるコードであるからだ。`stdin`から有限個の`input`しか受け付けないideoneがランタイムエラーを吐くのは仕方ないと言える。ちなみに、このエラーは`echo x`の後にbreakを挿入する事などで回避できるが、挙動は変わる。[こちら](http://ideone.com/vP29I7)では、`try-except`を使っており、おそらく挙動としては最も近い。

###when文 [When statement](http://nim-lang.org/docs/tut1.html#control-flow-statements-when-statement)
コード例:

[when.nim](http://ideone.com/jP7nz2)[^20]　

```nim
when system.hostOS == "windows":
  echo "Windowsで動かしていますね！"
elif system.hostOS == "linux":
  echo "Linuxで動かしていますね！"
elif system.hostOS == "macosx":
  echo "Mac OS Xで動かしていますね！"
else:
  echo "私の知らないオペレーション・システムです"
```

[^20]: どうやらideoneはlinuxを使っているようだ。（出力を見ながら）

`when`文は`if`文とほとんど同じだが、いくつかの違いを持つ。
- 書かれる条件式は全て、コンパイラが計算できるように定まった値を持たなくてはならない。
- 分岐内の文は新しいスコープを持たない。
- コンパイラは、構文を解析し、コンパイル時点で`true`だった最初の分岐の中の式のみをコンパイルする。

`when`文は各プラットフォームに適したコードをそれぞれ書くときに便利であり、C言語における`#ifdef`文と似ている。

一口メモ：コメントアウトするコードが大きい場合、普通のコメントを使うよりも`when false:`を使った方が良い事がよくある。この方法なら、ネストが可能だからだ。

##文とインデント [Statements and indentation](http://nim-lang.org/docs/tut1.html#statements-and-indentation)
基本的な制御文を押さえたところで、Nimのインデント規則の話題に戻ろう。

Nimにおいては、*単純文*と*複合文*が区別される。
*単純文*は他の文を含むことができない。
単純文に属するのは、代入文やプロシージャ呼び出し文、`return`文である。
一方、`if`、`when`、`for`、`while`といった*複合文*は他の文を含むことができる。
「曖昧さ回避」のため、複合文はインデントを必要とするが、単純文はインデントする必要はない。

[simple_complex_statement.nim](http://ideone.com/Ip2CIK)[^21]（注:コンパイルエラーを吐きます）[^22]

```nim
# 代入文が一つなので、インデントは必要ない
if x: x = false

# 入れ子構造のif文にはインデントが必要である
if x:
  if y:
    y = false
  else:
    y = true

# 条件式の後に文が二つ続くため、インデントが必要である。
if x:
  x = false
  y = false
```

[^21]: コードの最初のコメントは[原文](http://nim-lang.org/docs/tut1.html#statements-and-indentation)において、"no indentation needed for single assignment statement"と書かれている。この"single"は「一つの」と訳したが、"single statement"「単純」の間に"assignment"が割り込んでいると考えられない訳ではない。これを「一つの」と訳したのは、3つ目のコメントと比較してである。（3つ目は代入文が二つある）
[^22]: xもyも宣言されてないんだから、しょうがない。どうしても確認して安心したい方は[こちら](http://ideone.com/o5lKZx)。

式は通常、値を返し、文の一部である。
例として、if文中の条件式が挙げられる。
式の中にインデントを入れることで、可読性を高めることも可能である。

[indented_expression.nim]()（注:コンパイルエラーを吐きます）[^23]

```nim
if thisIsaLongCondition() and
    thisIsAnotherLongCondition(1,
       2, 3, 4):
  x = true
```

[^23]: 動くわけない。エラーのないコードは[こちら](http://ideone.com/PBCDM4)から

経験則として、式中のインデントが良いのは演算子・閉じていない括弧・コンマの後である。

括弧とセミコロン`(;)`を使うことで、式しか許されない場所でも文が使える。

[statement_as_expression.nim](http://ideone.com/QKAU3r)

```nim
# fac(4)、つまり4の階乗をコンパイル中に計算する
const fac4 = (var x = 1; for i in 1..4: x *= i; x)
```

##プロシージャ [Procudures](http://nim-lang.org/docs/tut1.html#procedures)
これまでのコード例で出てきた、[echo](http://nim-lang.org/docs/system.html#echo)、[readLine](http://nim-lang.org/docs/system.html#readLine,File)のような新しい命令を定義するには、*プロシージャ*という概念が必要となる。（*メソッド*や*関数*と呼ぶ言語もある[^24]）
Nimで新しいプロシージャを定義するには、`proc`というキーワードを使う。

[^24]: この文を読む限り、Nimにはメソッド・プロシージャ・関数の間に厳密な区別を設けようと考えてはなさそうだ。この中の日本語訳は「プロシージャ」で統一したが、別の意見があればコメントで勝手に討論してほしい。

[proc_yes.nim](http://ideone.com/I2lyDA)

```nim
proc yes(question: string): bool =
  echo question, " (はい/いいえ)"
  while true:
    case readLine(stdin)
    of "はい", "そうです", "可", "〇": return true
    of "いいえ", "ちがいます", "不可", "×": return false
    else: echo "「はい」か「いいえ」で明確に答えてください"

if yes("全ての君の重要なファイルを消そうか？"):
  echo "デイブ、申し訳ない。私には出来ない。"
else:
  echo "君も私と同じくらい、なにが問題かわかっているようだね。"
```

この例では、`yes`という名前のプロシージャが登場する。
`yes`は`question`に格納される質問をユーザーにした上で、「はい」やそれに似た返事に対してはtrueを、「いいえ」や似た返事に対してはfalseを返り値として返す。
`return`文があると、直ちにプロシージャから抜ける。（従って、whileループも抜ける）
コード例中の`(question :string): bool`という構文は、「`question`という`string`型のパラメータがあり、`bool`型の値を返すこと」を示す。
`bool`型（ブーリアン型）の話をすると、これは組み込みのデータ型であり、`true`と`false`しか有効な値を持たない。
また、if文やwhile文などの条件式はブーリアン型でなくてはいけない。

少し用語を解説しよう。コード例中の`question`は（正式な）[^25]パラメータと呼ばれ、`"全ての君の…"`の部分はパラメータに渡される*引数*と呼ばれる。

[^25]: [原文](http://nim-lang.org/docs/tut1.html#procedures)では"formal"となっているため「正式な」と訳したが、意味合いとしては「狭義の」と同じであると私は考えている。

###result変数 [Result variable](http://nim-lang.org/docs/tut1.html#procedures-result-variable)
返り値を返すプロシージャでは、返り値を表す`result`が暗黙に宣言されている。[^26]
式が後に続いていない`return`文は`return result`の省略形である。
出口の`return`が存在しないプロシージャは、終わる際に必ず、自動的に`result`の値を返す。
[^26]: 「暗黙に宣言されている」と言っても、実際には`proc hoge(): type =`の部分が宣言に相当している。現に、[`type`にどのデータ型を割り当てるかによって、resultの型も変わる](http://ideone.com/6iqRKq)。また、`type =`を抜かすと「resultが宣言されていない」という趣旨のエラーが返ってくる。

[result.nim](http://ideone.com/Lj8j90)

```nim
proc sumTillNegative(x: varargs[int]): int =
  for i in x:
    if i < 0:
      return
    result = result + i

echo sumTillNegative() # 0を出力する
echo sumTillNegative(3, 4, 5) # 12を出力する
echo sumTillNegative(3, 4 , -1 , 6) # 7を出力する
```

`result`変数はプロシージャの最初の行で宣言されており、'var result'と再宣言する事は、`result`変数を同じ名前の普通の変数で覆い隠し、本来の`result`変数が持つ機能を失う事を意味する。[^27]
result変数はプロシージャの返す型のデフォルト値で初期化[^28]されている。
参照型のresult変数は、プロシージャが宣言されたときは`nil`の値をとるため、状況に応じて、手動で初期化をしなくてはならない。

[^27]: [原文](http://nim-lang.org/docs/tut1.html#procedures-result-variable)では"shadow"とのみあるが、「本来の`result`変数が持つ機能を失う事を意味する」と補った。これは[具体的なコード例](http://ideone.com/8lyHjv)を見る限り、"shadow"はかなり強めの意味を持つからである。
[^28]: 初期値をイジれそうな方法はいくつか思いつく。私が思いついたのは[ブロック内で`result = initial_value`を書く](http://ideone.com/gEMIRl)、[`proc hoge() : type = initial_value`と宣言文で初期化する](http://ideone.com/skQEQe)、[パラメータ名をresultにする](http://ideone.com/4S6gP4)の3つである。どれが上手くいくかは、実際に確かめてみてほしい。また、他にうまくいった方法があれば、知らせてほしい。

###パラメータ [Parameters](http://nim-lang.org/docs/tut1.html#procedures-parameters)
プロシージャの中身に記述されたパラメータは、定数として扱われる。
つまり、何も変更しないと、パラメータの値は変えられないのだ。
というのもその方が、より効率的にコンパイラによるパラメータの受け渡しが出来るからである。
プロシージャ内でミュータブルな変数を使いたければ、プロシージャ内で`var`文を使って宣言しなければならない。
パラメータ名は上書き可能であり、それどころか、実は慣用的に用いられる。

[shadow_parameter.nim](http://ideone.com/Wul1t2)[^29]

```nim
proc printSeq(s: seq, nprinted: int = -1) =
  var nprinted = if nprinted == -1: s.len else: min(nprinted, s.len)
  for i in 0 .. <nprinted:
    echo s[i]
```

[^29]: ここでは関数の宣言のみをしている。実際に挙動を確かめたい人は`printSeq(@[1,2,3], 2)`などと打ち込むとよいだろう。

呼び出し先の引数をプロシージャで変えるには、`var`パラメータを使う。

[var_parameter.nim](http://ideone.com/HeIeGL)[^30]

```nim
proc divmod(a, b: int; res, remainder: var int) =
  res = a div b        # 整数型の除算
  remainder = a mod b  # 整数型のmod計算

var
  x, y: int
divmod(8, 5, x, y) # xとyを変更する
echo x
echo y
```

[^30]: [マニュアル](http://nim-lang.org/docs/manual.html#procedures)を読む限り、セミコロン`;`は単に見やすさの問題らしい。

コード例の中の`res`と`remainder`が*varパラメータ*である。
varパラメータはプロシージャで変更することが可能であり、呼び出し先にも引数の変更が伝わっている。[^31]
上の例では、varパラメータを使うよりも、タプルを返した方が適切であることは覚えておいてほしい。[^32]

[^31]: [原文](http://nim-lang.org/docs/tut1.html#procedures-parameters)中の"visible to the caller"の訳がよく分かっていない。文脈から察するに、「プロシージャ内に止まらず、呼び出し先にも変更が影響している」という意味だと判断したが、"visible"という単語のすわりが悪い。「見えている＝変化を知っている＝伝わっている」と考えて訳したが、「スコープ的な意味で見える」「プロシージャ宣言文を見なくても呼び出し先を見るだけで、プログラマにはどの変数が変えられたかが見て取れる」という解釈が無理とは思えない。（別解のうちの後者は"visible from"の方がニュアンスとしては近い）
[^32]: コード例は[こちらから](http://ideone.com/nOPJhc)
###discard文 [Discard statement](http://nim-lang.org/docs/tut1.html#procedures-discard-statement)
副作用として返り値を持つプロシージャを呼び出しつつ、その返り値を無視するには、`discard`文が**絶対に**必要である。

[discard_result.nim](http://ideone.com/vjbfMD)（注:`yes`プロシージャも定義してあります。）

```nim
discard yes("つまらない質問をしてもよろしいですか？")
```

呼び出したプロシージャやイテレータを宣言した際に`discardable`プラグマが使われていた場合、`discard`で明示的に示さずとも、返り値を無視できる。

[discardable_pragma.nim](http://ideone.com/cQYkqd)

```nim
proc p(x, y: int): int {.discardable.} =
  return x + y

p(3, 4) # 今は可能
```
[コメント](http://nim-lang.org/docs/tut1.html#comments)の項目で解説した通り、`discard`文はブロックコメントを作る時にも使える。

###名前付き引数 [Named arguments](http://nim-lang.org/docs/tut1.html#procedures-named-arguments)
プロシージャが多くのパラメータを持つ事はよくあり、その場合、パラメータの順番が分からなくなる。
これは特に、複雑なデータ型を形成するプロシージャでよく起こる。
従って、どの引数がどのパラメータに値を渡すのかを明確にするために、プロシージャに渡す引数は名前を付けることができる。

[create_window.nim]()（注:コンパイルエラーを吐きます[^33]）

```nim
proc createWindow(x, y, width, height: int; title: string;
                  show: bool): Window =
   ...

var w = createWindow(show = true, title = "My Application",
                     x = 0, y = 0, height = 600, width = 800)
```

今や我々は`createWindow`プロシージャを呼び出すのに、名前付き引数を使っているのであり、引数の順番は関係ない。
なお、順番引数と名前付き引数を混ぜるのは可能だが、可読性を欠く。

[mix_order_named_args.nim](http://ideone.com/KVqddJ)[^34]

```nim
var w = createWindow(0, 0, title = "My Application",
                     height = 600, width = 800, true)
```

パラメータが受け取る引数の個数が、丁度1個になる事はコンパイラによって確かめられる。
[^33]: `Window`型が定義されていないため、致し方ない。[dom](http://nim-lang.org/docs/dom.html#Window)というライブラリの中に、`Window`型がある。いろいろ調べてみたが、[javascriptプラットフォーム](http://nim-lang.org/docs/backends.html#backends-the-javascript-target)を使うくらいしか分からなかった。`nim js createWindow.nim`を実行するとエラーなく実行できたが非常に長いファイルで、読む気が失せたため、[Gist](https://gist.github.com/KTakahiro1729/7d29c73f43ae622e88ef062b78566d0e)で共有しておく。というより、私のような初心者プログラマにわかるわけない。
[^34]: エラーを回避するため、createWindowプロシージャの型は整数型にしてある。

###デフォルト値 [Default values](http://nim-lang.org/docs/tut1.html#procedures-default-values)
`createWindow`プロシージャを使いやすくするには、*デフォルト値*を持たせればいい。
呼び出し時に指定を受けない限り、このデフォルト値が引数として使われる。

[default_value.nim](http://ideone.com/1wmLyF)（注:コンパイルエラーを吐きます）[^33]

```nim
proc createWindow(x = 0, y = 0, width = 500, height = 700,
                  title = "unknown",
                  show = true): Window =
   ...

var w = createWindow(title = "My Application", height = 600, width = 800)
```

これで`createWindow`はデフォルト値と違う引数だけを指定すればよくなった。
デフォルト値を使って、パラメータの型推論が行われることを覚えておいてほしい。つまり例えば、`titel: string = "unknown"`と書く必要はない。


###プロシージャのオーバーロード [Overloaded procedures](http://nim-lang.org/docs/tut1.html#procedures-overloaded-procedures)
Nimでは、C++のようにプロシージャが上書きできる。

[overloaded_procedure.nim](http://ideone.com/drEmr4)[^35]

```nim
proc toString(x: int): string = ...
proc toString(x: bool): string =
  if x: result = "true"
  else: result = "false"

echo toString(13)   # toString(x: int)プロシージャを呼び出す
echo toString(true) # toString(x: bool)プロシージャを呼び出す
```

（`toString`が普通はNimの[$](http://nim-lang.org/docs/system.html#$)演算子で書かれることを覚えておいてほしい）
どのプロシージャが呼び出された`toString`として適切かは、コンパイラが選ぶ。
このオーバーロードを解決するアルゴリズムに関しては、ここではなくマニュアルで詳しく扱う。
とはいえ、思いつきもしない嫌なアルゴリズムではなく、比較的簡単な単一化のためのアルゴリズムに基づいている。
曖昧なプロシージャ呼び出しに対しては、エラーが返される。


[^35]: リンク先では`...`を`discard`と置き換えたが、つまらないため、[ローマ数字に置き換えるコード](http://ideone.com/ld7H4c)も書いてみた。あまり綺麗なコードではないので、参考にしない事。（アドバイスください）言うまでもないが、`$`にローマ数字に置き換える機能などない。

###演算子 [Operators](http://nim-lang.org/docs/tut1.html#procedures-operators)
Nimのライブラリでは、オーバーロードが非常によく使われる。
一つの理由としては挙げられるのは、`+`のような演算子それぞれが、まさにオーバーロードされたプロシージャである事だ。[^36]
中置表記`a + b`も前置表記も`+ a`パーサーで解釈できる。
中置表記の演算子は引数を必ず2つ取り、前置表記の演算子は必ず一つ取る。
後置表記があると、曖昧になるため、後置演算子は出来ない。
曖昧になるというのは例えば、`a @ @ b`が`(a) @ (@b)`と`(a@) @ (b)`のどちらを意味するのかが分からない、ということだ。
Nimでは後置表記をなくす事で、これは必ず`(a) @ (@b)`である事、が言えるようになったのである。

`and`、`or`、`not`などの、ほんのいくつかの組み込みの演算子を除き、演算子は以下の記号から構成される`+ - * \ / < > = @ $ ~ & % ! ? ^ . |`。
ユーザー定義の演算子は作れる。
`@!?+~ `という独自の演算子を定義することも可能だが、こんな演算子を定義した場合は可読性が損なわれるかもしれない。[^37]

演算子の計算の優先順序は、演算子の最初の文字で決まる。マニュアルに詳しい説明がある。

[^36]: [原文](http://nim-lang.org/docs/tut1.html#procedures-operators)では、"each operator like `+` is a just an overloaded proc"となっている。この"a just an"を私は知らないため、最初の"a"は誤植であると考え、"each operator like `+` is just an overloaded proc"と取り、「まさに」と訳した。ただ、「まさに」と受け取るには"just an"が微妙なので、誤訳の可能性は非常に高い。
[^37]: [原文](http://nim-lang.org/docs/tut1.html#procedures-operators)では、"`@!?+~` operator, but readability can suffer."となっている。これはスペース区切りでないため、`@!?+~`は一つの長い演算子と考える事が出来る。そのため、続く"but readability can suffer"も、この演算子を使う事を指しており、ユーザー定義の演算子について書いているわけではないと解釈した。（これがスペース区切りであった場合、「`@ ! ? + ~`といったよく使われる演算子をポンポン使うと可読性が低くなるぞ」という文章と取れなくもなくなる。実際にそんな事はないと思うけど）

新しい演算子を定義するには、演算子の記号をバックティック`` ` ` ``で挟めばいい。[^38]

[my_dollar.nim](http://ideone.com/Ud5EMr)[^39]

```nim
proc `$` (x: myDataType): string = ...
# オーバーロードの問題は解決できるため、今後は$演算子をmyDataTypeでも使える
# $演算子を他の演算子に対して使っても、作動することは保証されている
```

他のプロシージャを呼び出す時のように演算子を呼び出したい時も、`` ` ` ``記法が使える。

[call_operator.nim](http://ideone.com/hYOOhw)[^40] [^41]

```nim
if `==`( `+`(3, 4), 7): echo "True"
```

[^38]: 私のWindowsPCの日本語キーボードでは`SHIFT+@`で打ち込める。英語キーボードの場合、1の左にあることが多い。
[^39]: コンパイルエラーを避けるために、`type myDataType = object`を先頭に書き加えている。
[^40]: 念のため書いておくと、`\`==\`( \`+\`(3, 4), 7)`は`\`==\`(3 + 4, 7)`と同じであり、`3 + 4 == 7`とも同じである。
[^41]: 本当にどうでもいいことだが、Nimで真偽の真を意味するのはtrueではなく、Trueである。

###前方宣言 [Forward declarations](http://nim-lang.org/docs/tut1.html#procedures-forward-declarations)
全ての変数やプロシージャは、使う時点で宣言されている必要がある。
（というのも、Nimと同じくらい広くメタプログラミングが使えるプログラミング言語では同程度以上の事が必要になるのである）[^42]
しかし、相互再帰なプロシージャを使う場合、このルールに従うことが出来ない。
[^42]: この文章は文法が入り組んでいるので、少し解説しておく。[原文](http://nim-lang.org/docs/tut1.html#procedures-forward-declarations)は"The reason for this is that it is non-trivial to do better than that in a language that supports meta programming as extensively as Nim does."となっている。まず、全体の構造は"The reason for A is B."（Aである理由は、Bである）である。ここでAは"this"（＝前の文の「宣言されている必要がある」）、Bは"it is non-trivial ... Nim does"が対応する。次にBの構造は"it is C to D"（DすることはCだ）である。Cは"non-trivial"（＝些細でない（＝重要・必要なこと））であり、Dは"do better ... Nim does"となる。さらに、Dの構造を考えると"do better than E in F"（＝Fにおいては、Eよりも良くする）となる。ここで「良くする」というのは"better"を訳したものであるが、betterの意味はかなり広く、この文においては「より丁寧に・より十分に」くらいが当てはまるだろう。さて、Dの構造の中のE、Fに話を戻すと、Eは"that"（＝前の文の「宣言されている必要がある」）であり、Fは"a language that ... Nim does"である。Fは"a language"に"that"以下の"supports ... does"が掛かる構造をしており、"supports meta programming as extensively as Nim does"は「Nimと同じくらい広く、メタプログラミングを支援している」と直訳できる。あとは、この論理をまとめれば良いが、分かりにくいため意訳している。

[forward_declaration.nim](http://ideone.com/xlnnDX )[^43]（注:以下の両コードを含みます）

```nim
# 前方宣言
proc even(n: int): bool
```

```nim
proc odd(n: int): bool =
  assert(n >= 0) # nが負数になり無限ループする事がない事を保証する
  if n == 0: false
  else:
    n == 1 or even(n-1)

proc even(n: int): bool =
  assert(n >= 0) # nが負数になり無限ループする事がない事を保証する
  if n == 1: false
  else:
    n == 0 or odd(n-1)
```

コード例では、`odd`は`even`に依存し、逆もまたしかりである。
したがって、`even`を完全に定義する前であっても、コンパイラに`even`の存在を知らせる必要があるのだ。
そのための構文は簡単であり、`=`とプロシージャの中身を省略するだけでいい。
`assert`は境界条件を与えているに過ぎず、[モジュール](http://nim-lang.org/docs/tut1.html#modules)の項で触れる。

今後のNimのバージョンにおいては、前方宣言に要求されるものが減らされる。

コード例から分かるもう一つの事として、プロシージャの中身は単一の式だけでも十分だという事だ。
この場合、式の値が暗黙に返り値とされる。

[^43]: [原文](http://nim-lang.org/docs/tut1.html#procedures-forward-declarations)ではコード中のコメントに"negative recursion"と書かれているが、適切な訳が見つからなかった。恐らく、`n`が間違って負数になり、そのまま無限ループに陥ることを心配していると考えて、訳した。

#イテレータ以降の項は後編に含まれます

[後編へ](https://qiita.com/KTakahiro1729/items/3f18811267bf4f8075d5#_reference-cbbfacf6fa955fc51b49)

#訳注