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

だいぶさぼっている間にnimのバージョンが0.17.2になっていました。途中にバージョンの壁があるかもしれません。古いバージョンの訳があったらコメントに書いておいてください。

[前編はこちら](https://qiita.com/KTakahiro1729/items/f4776f3a072c01f9086b)

##イテレータ [Iterators](http://nim-lang.org/docs/tut1.html#iterators)
1から10までを単に数え上げるだけの、退屈なコード例に話を戻そう。

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

```nim
echo "10まで数える: "
for i in countup(1, 10):
  echo $i
```

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

このループで使われているcountupプロシージャは自分で書けるだろうか？試してみよう。

[countup_iterator.nim](http://ideone.com/et6SkI)[^2]

```nim
proc countup(a, b: int): int =
  var res = a
  while res <= b:
    return res
    inc(res)
```

[^2]: このリンク先ではコンパイルエラーを起こしている。しかし、これはあまり本質的なところでエラーを返しているわけではない。というのも、「イテレータを使うべきところでプロシージャを返している」というのは、コンパイルエラーの類ではなく、論理エラーであるからだ。[こちら](http://ideone.com/g12LN4)ではプロシージャ名を少しいじったうえで、本質的なエラーを返してもらっている。

しかしながら、このコードは上手くいかない。
このプロシージャの問題点は、値を返すだけ（`return`）だという点だ。
私たちは、returnの後、次のループへ`continue`するものを求めているのだ。
この*return*と*continue*を合わせたものこそが*yield*文である。
コードを`yield`文で修正したら、あとは、`proc`キーワードを`iterator`に書き換えればいい。
初めてのイテレータの出来上がりだ。

[countup1.nim](http://ideone.com/1a8AsK)

```nim
iterator countup(a, b: int): int =
  var res = a
  while res <= b:
    yield res
    inc(res)
```

イテレータはプロシージャと非常に似ているが、重要な違いが数点ある。
- イテレータはforループ処理でしか呼び出せない
- イテレータ中に`return`文を記述できず、プロシージャ中に`yield`文が記述できない
- イテレータでは`result`変数が暗黙に宣言されない
- イテレータは再帰ができない
- イテレータは前方宣言できない。というのも、コンパイラによってインライン展開出来るようにイテレータは書かれている必要があるからである。（今後のバージョンのコンパイラでは、この制限はなくなる）

`clojure`イテレータには、これらとは別の制限がつく。詳細は[第一級イテレータ](http://nim-lang.org/docs/manual.html#iterators-and-the-for-statement-first-class-iterators)を見てほしい。
同じ名前のプロシージャとイテレータでも本質的には別の名前空間を持つことから、とあるプロシージャと同じ名前、パラメータを持ったイテレータを作ることが出来る。
このため、イテレータの返す値を同じ名前のプロシージャがシーケンスとしてまとめて返すことは頻繁に見られる。
例として、[strutilsモジュール](http://nim-lang.org/docs/strutils.html)の`split`が挙げられるだろう。


##基本的なデータ型 [Basic types](http://nim-lang.org/docs/tut1.html#basic-types)
このセクションでは、基本的な組み込みデータ型やそこで使える演算子について詳しく取り扱う。

###ブーリアン型 [Booleans](http://nim-lang.org/docs/tut1.html#basic-types-booleans)
Nimではブーリアン型を`bool`と呼び、`true`か`false`という前もって定義された二値の一方しかとりえない。
while, if, elif when文の条件分岐はブーリアン型を返さなくてはならない。

ブーリアン型で使える演算子として、`not`、`and`、`or`、`xor`、`<`、`<=`、`>`、`>=`、`!=`、`==`が定義されている。
`and`と`or`演算子では真偽の評価を端折ることがある。例えば

[while_and.nim](http://ideone.com/NweuKs)（注: コンパイルエラーを起こします[^3]）

```nim
while p != nil and p.name != "xyz":
  # p == nil　の場合、p.nameの真偽は評価されない 
  p = p.next
```

[^3]: pが定義されていないというエラーが出てくる。そこで`var p : string`を加えてみると、p.nameが定義されていないと出てくる。端折るのは飽くまでもランタイム時だけで、コンパイル時に無視してくれる訳ではない。（そりゃそうか）問題なく動くのは[こちら]()
である。

###文字型 [Characters](http://nim-lang.org/docs/tut1.html#basic-types-characters)
Nimでは、文字型を`char`型と呼び、大きさは1バイトである。
したがって、ほとんどのUTF-8文字を表現出来ない、とはいえ、マルチバイトUTF-8文字の一バイト分は表現できる。
効率を優先したのが理由だ。
しかし、UTF-8の使用頻度は圧倒的に多く、作ったプログラムはUTF-8を問題なく扱える。
これはUTF-8が、この用途のために使われたからである。[^4]
char型リテラルは単引用符で囲まれる。

文字型は`==`、`<`、`<=`、`>`、`>=`演算子で比較できる。
`$`演算子は`char`型を`string`型に変換する。
文字型は整数型を混ぜて使うことは出来ず、`char`型から文字番号を得るには`ord`プロシージャを使う。
整数をASCIIで対応する`char`型に変換するには`chr`プロシージャを使う。[^5]

[^4]: [原文](http://nim-lang.org/docs/tut1.html#basic-types-characters)を取り違えている可能性がある。特に、"the resulting programs will still handle UTF-8 properly"が未だに再現できていない。また、"as UTF-8 was specially designed for this"のthisの意味も取りかねている。というのも、UTF-8の思想が「8bit単位で処理する」で有ると同時に、それにより、「一部の文字において処理速度を上げる」と複雑だからであり、たぶん、その他諸々もあるからである。どれ？
[^5]: ASCIIで対応する、という事は実際にコードを走らせることで確認したうえで補った。


###文字列型 [Strings](http://nim-lang.org/docs/tut1.html#basic-types-strings)
文字列型の値は**ミュータブル**であり、かなり効率的に文字列を追加できる。
Nimの文字列はNull終端であり、フィールド長を持つ。
文字列のフィールド長は組み込みの`len`プロシージャで得られる。
ただしこの際、終端のNull文字は頭数に入れられない。
終端のNull文字を呼び出しても、エラーではなく、より簡単なコードに繋がることがよくある。

[nullTerminal.nim](http://ideone.com/euAcKM)（※コンパイルエラーを回避するために数か所加筆してあります）

```nim
if s[i] == 'a' and s[i+1] == 'b':
  # ``i < len(s)``であるか否かを調べなくても良いのだ！
  ...
```

文字列に代入演算子を使うと、文字列をコピーできる。
文字列を連結するには`&`演算子を、追加するには`add`を用いる。

文字列の比較では辞書的な順序が使われる。
すべての比較演算子が使える。

すべての文字列は慣習的にUTF-8の文字列であるが、強制ではない。
例えば、バイナリファイルから読み取られた文字列は単にバイトを並べた物に過ぎない。
この場合、`s[i]`というインデックス操作はsのi番目の*char*を返すのであり、sのi番目の*unichar*を返すわけではない。

文字列の`nil`という特別な値を初期値に持つ。
しかし、ほとんどの文字列演算子は`nil`を扱えない。（エラーに繋がる）
そのため、空の文字列には`nil`より`""`を使うべきである。
しかし、`""`を使うとヒープ領域に文字列オブジェクトが作られるため、かねあいを考える必要がある。[^6]

[^6]: [原文](http://nim-lang.org/docs/tut1.html#basic-types-characters)では、"often creates a string object on the heap"とあるが、"often"を訳していない。場合によって作ったり、作らなかったりするの？
###整数型 [Integers](http://nim-lang.org/docs/tut1.html#basic-types-integers)
Nimは以下の整数型が組み込まれている
`int int8 int16 int32 int64 uint uint8 uint16 uint32 uint64`

デフォルトの整数型は`int`である。
整数型リテラルは*型指定の接尾辞*を用いてほかの整数型に変更できる。

[intVariable.nim](http://ideone.com/9hucOF)

```nim
let
  x = 0     # xの型は``int``である
  y = 0'i8  # yの型は``int8``である
  z = 0'i64 # zの型は``int64``である
  u = 0'u   # uの型は``uint``である
```

整数型が最もよく使われるのは、メモリ中のオブジェクトを数える為であり、`int`はポインタと同じ大きさを持つ。

整数型では、よく使われる演算子である`+ - * div mod < <= == != > >=`が定義されている。
また、整数型では`and or xor not`演算子も定義されており、ビット演算子が使えるようになっている。
左シフト演算子は`shl`であり、右シフト演算子は`shr`である。
ビットシフト演算子は被演算子[^7]を*符号なし*整数として扱う。
算術シフトに関しては掛け算や割り算を使えばよい。

符号がない整数を含む演算ではラップアラウンドが起き、オーバーフロー、アンダーフローが起きない。

異なる種類の整数型が使われる式では自動型変換が行われる。
しかし型変換で情報が失われる場合[^8]、EOutOfRange例外がraiseされる。（コンパイル時にエラーが見つからない場合）

[^7]: [原文](https://nim-lang.org/docs/tut1.html#basic-types-integers)中では、"argument"（引数）となっているが、演算子にとって正確な語は"operand"（被演算子）であると考えた。ただ、Nimにおいては演算子は[プロシージャと同じように宣言したら作れる](http://qiita.com/KTakahiro1729/items/f4776f3a072c01f9086b#%E6%BC%94%E7%AE%97%E5%AD%90-operators)事を考えると、原文中の"argument"が不適切とも言えない。
[^8]: おそらく、「7.1(浮動小数点数)を7(整数型)にする」のように、「0.1という情報が失われる」という状況を想定しているのだろうが、どういう型変換をしたら、そうなるのか分からない…

###浮動小数点型 [Floats](http://nim-lang.org/docs/tut1.html#basic-types-floats)
Nimは以下の浮動小数点型が組み込まれている`float float32 float64`。

デフォルトの浮動小数点型は`
float`である。
現在実装されているものでは、`float`は常に64bitの大きさである。

浮動小数点型リテラルは*型指定の接尾辞*を用いてほかの浮動小数点型に変更できる。

[floats.nim](https://ideone.com/I8xp7j)

```nim
var
  x = 0.0      # xの型は``float``である
  y = 0.0'f32  # yの型は``float32``である
  z = 0.0'f64  # zの型は``float64``である
```

浮動小数点型では、よく使われる演算子である+ - * / < <= == != > >=が定義され、IEEE規格に沿う。

異なる種類の浮動小数点型が使われる式では自動型変換が行われる。より小さい型が大きい型に変換されるのである。
整数型が自動的に浮動小数点型に変換されることは*ない*。逆も同様だ。
[toInt](https://nim-lang.org/docs/system.html#toInt)や[toFloat](https://nim-lang.org/docs/system.html#toFloat)プロシージャがこれらの型変換には使える。


###型変換 [Type conversion](http://nim-lang.org/docs/tut1.html#basic-types-type-conversion)
基本的な型同士の変換は、型を関数として使うことで行える。

[type_conversion.nim](https://ideone.com/fA9OM4)

```nim
var
  x: int32 = 1.int32   #int32(1)を呼び出すのと同様
  y: int8  = int8('a') # 'a' == 97'i8
  z: float = 2.5       # int(2.5)で2に丸められる
  sum: int = int(x) + int(y) + int(z) # sum == 100
```

##データ型の内部表現 [Internal type representation](http://nim-lang.org/docs/tut1.html#internal-type-representation)
先に述べたように、組み込みの[$](https://nim-lang.org/docs/system.html#$)（文字列化）演算子はどんな基本的な型でも、文字列に変換する。これにより`echo`プロシージャで出力できる。
しかし、より高度な型や自分自身で定義した型は`$`演算子を使っても、自分自身で定義するまでは上手くいかない。
`$`演算子を書かずに、その複雑な型の値をデバックしたいだけ、という時がある。
そんな時は[repr](https://nim-lang.org/docs/system.html#repr)が使える。これは閉路を含むような参照構造を持ったデータでも使える[^9]。
以下の例では、基本的な型の間ででも`$`と`repr`の出力が異なることを示している。

[internal.nim](https://ideone.com/44jwcg)[^16]

```nim
var
  myBool = true
  myCharacter = 'n'
  myString = "nim"
  myInteger = 42
  myFloat = 3.14
echo myBool, ":", repr(myBool)
# --> true:true
echo myCharacter, ":", repr(myCharacter)
# --> n:'n'
echo myString, ":", repr(myString)
# --> nim:0x10fa8c050"nim"
echo myInteger, ":", repr(myInteger)
# --> 42:42
echo myFloat, ":", repr(myFloat)
# --> 3.1400000000000001e+00:3.1400000000000001e+00
```

[^9]: ~~原文では"complex data graphs with cycles"となっている。調べたがどんな意味だろうか…"data graph"と言っている以上、グラフ理論のほうを指しているとは思えないのだが…~~ コメント参照。訳は@243f6a8885a308d313198a2e037 さんのものを丸パクリしました。

[^16]: コメントで示している出力、ideoneの出力、nim ver0.17.2の出力はそれぞれ異なった。（ideoneはtrue:true、n:'n'、nim:0x2b2c01b7a050"nim"、42:42、3.14:3.14。ver0.17.2はideoneはtrue:true、n:'n'、nim:000000000016F058"nim"、42:42、3.14:3.14。


##高度なデータ型 [Advanced types](http://nim-lang.org/docs/tut1.html#advanced-types)

[biggetst.nim](https://ideone.com/Kl1pdl)

```nim
type
  biggestInt = int64      # 使える最大の整数型
  biggestFloat = float64  # 使える最大のfloat型
```

列挙型とオブジェクト型を定義するには`type`文が必要である。[^10]

[^10]: [原文](http://nim-lang.org/docs/tut1.html#advanced-types)では、"cannot be defined on the fly, but only within a  type statement."と非常にややこしいことになっているが、"not ~ but"と解釈し、また"on the fly"（直訳は「急いで」）を`var`や`type`といったものを置かずに、と解釈した。

###列挙型 [Enumerations](http://nim-lang.org/docs/tut1.html#advanced-types-enumerations)
列挙型の変数には有限集合の値しか代入することができない。
この集合とは順番に並んだ識別子である。
各識別子には、内部的に整数型が代入されている。
実行時では、最初の識別子に0、二番目に1、以下同様、といった風に代入されている。
例:

[enums.nim](https://ideone.com/xCD5bN)

```nim
type
  Direction = enum
    north, east, south, west

var x = south      # `x`は`Direction`型。値は`south`
echo $x           # "south"を`stdout`に書く
```

列挙型なら全て、比較演算子が使える。
曖昧さをなくすため、`Direction.south`という列挙型の識別子が使える。

`$`演算子はどんな列挙型でもその名前に変換し、`ord`プロシージャは内部的に使われている整数値を返す。

ほかの言語とよりよく親和するために[^11]、enum型の識別子に明示的に順序型の値[^12]を代入することができる。
ただし、その順序型の値は昇順でなくてはならない。
順序型の値が明示的に与えられていない識別子は、ひとつ前の値+1の順序型値を代入される。

明示的に定義された列挙型は**穴開き**でもよい。

(holy_enum.nim)[https://ideone.com/iBXiDm]

```nim
type
  MyEnum = enum
    a = 2, b = 4, c = 89
```

[^11]: 親和という言葉を使っているが、本来はinterfaceという言葉である。よりよく接するため、というニュアンスから意訳した。

###順序型 [Ordinal types](http://nim-lang.org/docs/tut1.html#advanced-types-ordinal-types)
跳んだ値のない列挙型、整数型、`char`、`bool`（と部分範囲型）は順序型と呼ばれている。順序型にはかなり多くの特別な演算が出来る。

|操作|注|
|---|---|
|`ord(x)`|xの値を表すのに使われている整数を返す|
|`inc(x)`|xを1だけインクリメントする|
|`inc(x, n)`,|xをnだけインクリメント。ただしnは整数|
|`dec(x)`|xを1だけデクリメントする|
|`dec(x, n)`,|xをnだけデクリメントする。ただしnは整数|
|`succ(x)`|xの後に来る値を返す|
|`succ(x, n)`|xのn番目後に来る値を返す。ただしnは整数|
|`pred(x)`|xの前に来た値を返す|
|`pred(x, n)`|xのn番目前に来た値を返す。ただしnは整数|

この[inc](https://nim-lang.org/docs/system.html#inc)、[pred](https://nim-lang.org/docs/system.html#dec)そして[pred](https://nim-lang.org/docs/system.html#pred)操作は**EOutOfRange**や**EOverflow**という例外を吐いて失敗することがある。
###部分範囲型 [Subranges](http://nim-lang.org/docs/tut1.html#advanced-types-subranges)

部分範囲型はある範囲内の値を整数型や列挙型（元にする型）から取り出したものである。
例：

[subrange.nim](https://ideone.com/tD99U8)

```nim
type
  MySubrange = range[0..5]
```

**MySubrange**は0から5までの値しか持てない**int**の部分範囲型である。
**MySubrange**で使える値以外を代入すると、コンパイル時エラーや実行時エラーになる。
ある型から、それを元に作った部分範囲型への代入（とその逆）が可能である。

**system**モジュールでは、重要な型である[自然数型](https://nim-lang.org/docs/system.html#Natural)が`range[0..high(int)]`([`high`](https://nim-lang.org/docs/system.html#high)は最大値を返す）として定義されている。
ほかのプログラミング言語では、符号なし整数型を自然数として使うことを勧めているかもしれない。
しかしこれは多くの場合**賢くない**。というのも、負の数を取らない、というだけの理由で、（ラップアラウンドしてしまう）符号なし型の計算方法を使うのは好ましくないからだ。
Nimの**Natural**型は、このようなよくあるプログラミングのエラーの回避に役立つ。



###集合型 [Sets](http://nim-lang.org/docs/tut1.html#advanced-types-sets)
集合型は数学的な集合の概念をモデルにしている。集合型が元にする型は**特定の大きさを持つ順序型のみである。すなわち：**

 - `int8`-`int16`
 - `uint8`/`byte-uint16`
 - char
 - enum

やこれと同等のものである。
これは集合型が高パフォーマンスなビットベクトルとして実行されることが理由である。
もっと大きな型で集合型を宣言しようと試しても、エラーに終わる。

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

```nim
var s: set[int64] #Error: set is too large　（訳　エラー: 集合が大きすぎます）
```

集合を作るには集合コンストラクタを使う、`{}`が空集合だ。
空集合は要素を持つ集合型とも適合する。[^12]
コンストラクタは要素（や要素の範囲）を挟むことでも使える。

[letters.nim](https://ideone.com/jviaL7)　（注：ideoneのコードには出力の行を加えています）

```nim
type
  CharSet = set[char]
var
  x: CharSet
x = {'a'..'z', '0'..'9'}  # これは'a'から'z'までの文字と、'0'から'9'までの数字を含む集合を作った
```

集合では以下の演算が使える。

|演算|意味|
|---|---|
|`A + B`|二つの集合の和集合|
|`A * B`|二つの集合の積集合（共通部分）|
|`A - B`|二つの集合の差集合（AからBの要素を除いたもの）|
|`A == B`|集合の同等性|
|`A <= B`|包含関係（AはBの部分集合あるいは同じ集合）|
|`A < B`|狭義の包含関係（AはBの狭義の部分集合）|
|`e in A`|帰属関係（Aは要素eを含む）|
|`e notin A`|Aは要素eを含まない|
|`contains(A, e)`|Aは要素eを含む|
|`card(A)`|Aの濃度（Aの要素の数）|
|`incl(A, elem)|`A = A + {elem}`と同じ|
|`excl(A, elem)`|`A = A - {elem}`と同じ|

集合型がよく使われるのは、プロシージャの*フラグ*の型を定義する時である。
この方法は、整数の定数を作り**or**でまとめるよりも、美しい。（型安全でもある）

[^12]: "concrete set type"を「要素を持つ集合型」と訳した。ちなみに「元」と「要素」とで悩んだ。


###配列型 [Arrays](http://nim-lang.org/docs/tut1.html#advanced-types-arrays)
配列は単純な固定長のコンテナである。
配列内の要素はすべて同じ型である。
配列のインデックスはどんな順序型でもよい。[^13]

配列は`[]`で作れる。

(arrays.nim)[https://ideone.com/tqcWzK]

```nim
type
  IntArray = array[0..5, int] # 0..5がインデックスの配列
var
  x: IntArray
x = [1, 2, 3, 4, 5, 6]
for i in low(x)..high(x):
  echo x[i]
```

`x[i]`という記法は`x`のi番目の要素にアクセスするために用いられる。
配列へのアクセスは常に境界値チェックされる（コンパイル時、実行時）。
これらのチェックを無効化するには、はプラグマによって、つまりコンパイラーを`--bound_checks:off`というコマンドラインスイッチで呼び出す。[^14]

配列はほかのNimの型のように値型である。
代入演算子は配列の中身を丸ごとコピーする。

組み込みの[len](https://nim-lang.org/docs/system.html#len,TOpenArray)プロシージャは配列の長さを返す。[low(a)](https://nim-lang.org/docs/system.html#low)は最小の有効なインデックスを返し、[high](https://nim-lang.org/docs/system.html#high)は最大のインデックスを返す。

[nested_array.nim](https://ideone.com/4HJ3pt)[^17]

```nim
type
  Direction = enum
    north, east, south, west
  BlinkLights = enum
    off, on, slowBlink, mediumBlink, fastBlink
  LevelSetting = array[north..west, BlinkLights]
var
  level: LevelSetting
level[north] = on
level[south] = slowBlink
level[east] = fastBlink
echo repr(level)  # --> [on, fastBlink, slowBlink, off]
echo low(level)   # --> north
echo len(level)   # --> 4
echo high(level)  # --> west
```

[^17]: "invalid data!"っていう見るからにやばそうな出力がある。0.17.2ではコメント通りの出力。

ほかの言語におけるネストされた配列（多次元）の構文では、かっこを増やすことになる。というのも通常、各次元のインデックスの型はほかの次元の型と同じ型に縛られているからだ。
Nimにおいては、異なる次元では異なる型のインデックスを持てる。そのため、インデックスのネストは少々異なる。
levelがenumの配列として定義され、enumがまた別のenumによりインデックスを振られていた直前の例を元にして、以下の数行を加えることで、整数型のインデックスからアクセスできるlight tower 型を加えることが出来る。

[more_nested_array.nim](https://ideone.com/F4Qd9y)[^18]

```nim
type
  LightTower = array[1..10, LevelSetting]
var
  tower: LightTower
tower[1][north] = slowBlink
tower[1][east] = mediumBlink
echo len(tower)     # --> 10
echo len(tower[1])  # --> 4
echo repr(tower)    # --> [[slowBlink, mediumBlink, ...more output..
# 以下の行は型の不一致のエラーによりコンパイルできない
#tower[north][east] = on
#tower[0][1] = on
```

[^18]: "invalid data!"っていう見るからにやばそうな出力がある。0.17.2ではコメント通りの出力。

組み込み`len`プロシージャが配列の最初の次元の長さしか返さない様子に注目してほしい。
ネストされている様子をよりよく可視化できる`LightTower`を定義するもう一つの方法は、以前の`LevelSetting`型の定義を除き、その代わりに最初の次元の型として埋め込まれているものとして書くことである。

[embed.nim](https://ideone.com/5wB16e)

```nim
type
  LightTower = array[1..10, array[north..west, BlinkLights]]
```

配列が0から始まることはよくあるため、簡略化された構文で0から（指定された値-1）までの範囲を指定できる。

[shorthand_range](https://ideone.com/pGia58)

```nim
type
  IntArray = array[0..5, int] # 0..5の要素を持つ配列
  QuickArray = array[6, int]  # 0..5の要素を持つ配列
var
  x: IntArray
  y: QuickArray
x = [1, 2, 3, 4, 5, 6]
y = x
for i in low(x)..high(x):
  echo x[i], y[i]
```


[^13]: [x['A']とかできる](https://ideone.com/fcmzPY)
[^14]: "pragma or invoking the compiler .."となっていたが、プラグマとコマンドラインスイッチは同じなので、「つまり」と訳した。

###シーケンス型 [Sequences](http://nim-lang.org/docs/tut1.html#advanced-types-sequences)
シーケンス型は配列の可変長なものに似ており、その長さは（文字列のように）実行時に変えられる。
シーケンス型が可変長なため、ヒープ領域に割り当てられ、ガーベジコレクションの対象である。

シーケンス型は常に、0から始まる`int`でインデックスされる。[len](https://nim-lang.org/docs/system.html#len,seq[T])、[low](https://nim-lang.org/docs/system.html#low)や[high](https://nim-lang.org/docs/system.html#high)
による演算はシーケンス型でも使える。
`x[i]`という記法は`x`のi番目の要素にアクセスするために使える。

シーケンスを作るには、配列のコンストラクタの`[]`に配列からシーケンス型を変換する演算子である`@`を組み合わせる。
シーケンス型に領域を割り当てるもう一つの方法は組み込みの[newSeq](https://nim-lang.org/docs/system.html#newSeq)プロシージャを使うことである。

シーケンスはオープン配列パラメータに渡すことが出来る。
例：

[array_to_seq.nim](https://ideone.com/6RoRiI)

```nim
var
  x: seq[int] # 整数のシーケンスへの参照
x = @[1, 2, 3, 4, 5, 6] # @により配列がヒープに割り当てられたシーケンスへと変換される
```

シーケンス型の変数は`nil`で初期化される。
しかし、ほとんどのシーケンス型の演算子はパフォーマンスの事情で`nil`に対処できない。（例外エラーを引き起こすことにつながる）
したがって、*空*値には`@[]`のほうが`nil`よりも使うべきである。
しかし、`@[]`はヒープ領域にシーケンスのオブジェクトを作るため、ここではトレードオフの関係がある。

シーケンスを使うとき`for`文は1つないし2つの変数を持つことが出来る。
一変数形式を用いる場合、その変数はシーケンス型から渡される値を保持する。
`for`文は[system](https://nim-lang.org/docs/system.html)モジュールの[items()](https://nim-lang.org/docs/system.html#items.i,seq[T])からの返り値に基づいてループする。
しかし、二変数形式を使った場合、最初の変数はインデックス位置を保持し、二つ目の変数は値を保持する。
この場合、`for`文は[system](https://nim-lang.org/docs/system.html)モジュールの[pairs()](https://nim-lang.org/docs/system.html#pairs.i,seq[T])からの返り値に基づいてループする。

[for_types.nim](https://ideone.com/o3miKK)

```nim
for value in @[3, 4, 5]:
  echo value
# --> 3
# --> 4
# --> 5

for i, value in @[3, 4, 5]:
  echo "index: ", $i, ", value:", $value
# --> index: 0, value:3
# --> index: 1, value:4
# --> index: 2, value:5
```

###オープン配列型 [Open arrays](http://nim-lang.org/docs/tut1.html#advanced-types-open-arrays)
注意：オープン配列型はパラメータでのみ使われる

固定長の配列があまりに融通が利かないことはよくある。プロシージャが様々な長さの配列に対応しなくてはならなくなる。
オープン配列型はこの対応を可能にする。
オープン配列は常に、0から始まる`int`型でインデックスされる。[len](https://nim-lang.org/docs/system.html#len,seq[T])、[low](https://nim-lang.org/docs/system.html#low)や[high](https://nim-lang.org/docs/system.html#high)演算子はオープン配列でも使える。
どんな配列も型が対応していれば、オープン配列パラメータに渡すことができ、インデックスの型は関係ない。

[open_array.nim](https://ideone.com/kFJlJj)

```nim
var
  fruits:   seq[string]       # 'nil'で初期化されている文字列への参照
  capitals: array[3, string]  # 文字列の固定長配列

fruits = @[]                  # 'fruits'として参照される空っぽのシーケンスをヒープ領域に作る

capitals = ["New York", "London", "Berlin"]   #'capitals'配列は3つの変数の代入しか認めない
fruits.add("Banana")          # 'fruits'シーケンスは実行時に動的に拡大される
fruits.add("Mango")

proc openArraySize(oa: openArray[string]): int =
  oa.len

assert openArraySize(fruits) == 2     # プロシージャはシーケンスをパラメータとして受け入れる
assert openArraySize(capitals) == 3   # のみならず配列型も受け入れる
```

オープン配列パラメータはネストできない。多次元オープン配列パラメータがないのは、めったに必要にならず、効率的に実装できないからである。

###可変引数 [Varargs](http://nim-lang.org/docs/tut1.html#advanced-types-varargs)
`varargs`パラメータはオープン配列パラメータに似ている。
しかし、多様な数の引数をプロシージャに渡すことを実装する手段でもある。
コンパイラーは引数の並びを自動的に配列へと変換する。

[varargs](https://ideone.com/BNt9XQ)

```nim
proc myWriteln(f: File, a: varargs[string]) =
  for s in items(a):
    write(f, s)
  write(f, "\n")

myWriteln(stdout, "abc", "def", "xyz")
# はコンパイラにより変換されて、
myWriteln(stdout, ["abc", "def", "xyz"])
```

この変換は可変引数パラメータがプロシージャのヘッダ[^15]の最後のパラメータの時のみ行われる。
以下の状況では、型変換も行える。

[varargs_str](https://ideone.com/rrQiIm)

```nim
proc myWriteln(f: File, a: varargs[string, `$`]) =
  for s in items(a):
    write(f, s)
  write(f, "\n")

myWriteln(stdout, 123, "abc", 4.0)
# はコンパイラにより変換されて、
myWriteln(stdout, [$123, $"abc", $4.0])
```

この例では、パラメータ`a`に渡されたどの変数にも[$](https://nim-lang.org/docs/system.html#$)が適用されている。
文字列に適用された[$](https://nim-lang.org/docs/system.html#$)は何もしていないことに注意してほしい。

[^15]: 関数ヘッダのほうが一般的な表現かもしれない

###スライス [Slices](http://nim-lang.org/docs/tut1.html#advanced-types-slices)

スライスは構文上、部分範囲型によく似ているが、別の状況で使われる。
スライスは単に、スライス型のオブジェクトであり、二つの境界値、*a*と*b*を持つ。
スライスは単独ではあまり役に立たない。しかし他のコレクションにおいて、範囲を指定するためにスライスが使える。

[slice.nim](https://ideone.com/pC6LrO)

```nim
var
  a = "Nim is a progamming language" #訳：Nimはプログラミング言語である
  b = "Slices are useless." #訳：スライスは役立たず

echo a[7..12] # --> 'a prog'  #訳：はプログ
b[11..^2] = "useful"  #訳：役立つ
echo b # --> 'Slices are useful.' #スライスは役立つ
```

直前の例において、スライスは文字列の一部を編集することに使われた。
スライスはその型で使えるどんな値でも扱えるが、どんな型が使えるかはスライスを使うプロシージャが決める。

> 文字列、配列、シーケンスなどのインデックスを指定する様々な方法を知るには、Nimが0始まりのインデックスを使うことを覚えておかなくてはならない。
> 
> 文字列`b`の長さは19であり、インデックスを指定する方法は二通りある。

```
"Slices are useless."
 |          |     |
 0         11    17   インデックスを使用
^19        ^8    ^2   ^構文を使用
```

> ここでは`b[0..^1]`は`b[0..b.len-1]`や`b[0..<b.len]`に等しく、`^1`が`b.len-1`を指定する簡単な方法を提供していることがわかる。
>
> 上の例は文字列がピリオドで終わっているため、"useless"を除いて"useful"にするには"useless"部分が`b[11..^2]`であるため、`b[11..^2] = "useful"`が"useless"部分を"useful"に置き換え、"Slices are useful."を返す。
> 
> 注意：この代替法は`b[^8..^2] = "useful"`だったり、`b[11..b.len-2] = "useful"`だったり、`b[11..<b.len-1] = "useful"`だったり……


###タプル型 [Tuples](http://nim-lang.org/docs/tut1.html#advanced-types-tuples)
タプル型は様々な名前の*フィールド*や領￥フィールド域の*順序*を定義する。
タプルを作るうえで、コンストラクタである`()`が使える。
両機の順序はタプルの定義の順序と一致しなくてはいけない。
異なったタプル型は、フィールドを同じ型で同じ名前で同じ順序で指定しているとき、*同等*となる。

[tuples.nim](https://ideone.com/PYJUMV)

```nim
type
  Person = tuple[name: string, age: int] # 人物を表現するタプル
                                         #人物は名前と年齢により構成されている
var
  person: Person
person = (name: "Peter", age: 30)
# 同じだがより可読性が低いもの
person = ("Peter", 30)

echo person.name # "Peter"
echo person.age  # 30

echo person[0] # "Peter"
echo person[1] # 30

# 異なるtypeのセクションでタプルを宣言する必要はない
var building: tuple[street: string, number: int]
building = ("Rue del Percebe", 13)
echo building.street

# 以下のコードはコンパイルできない。異なるタプルだからだ。
#person = building
# --> Error: type mismatch: got (tuple[street: string, number: int])
#     but expected 'Person'

# 以下のコードは、フィールドの名前と型が同じなため、動く
var teacher: tuple[name: string, age: int] = ("Mark", 42)
person = teacher
```

タプルを使うために型を宣言する必要はないが、別のフィールド名で作られたタプルはフィールドの型が同じであっても別のオブジェクトとして認識される。

タプルは変数の代入の時に*展開*される。（そしてこの時だけ！）
これはタプルのフィールドを、それぞれの名前を持つ変数に代入するうえで便利だ。
この例として、[os](https://nim-lang.org/docs/os.html)モジュール内の[splitFile](https://nim-lang.org/docs/os.html#splitFile)プロシージャがある。これはディレクトリ名、ファイル名、ファイルの拡張子にを同時に返す。
タプルの展開をするには、展開された値を代入したい変数をかっこで囲む必要がある。そうしないと、すべての変数に同じ値を代入することになる！
例えば、

[spitfire.nim](https://ideone.com/ppiy5d)

```nim
import os

let
  path = "usr/local/nimc.html"
  (dir, name, ext) = splitFile(path)
  baddir, badname, badext = splitFile(path)
echo dir      # 出力は `usr/local`
echo name     # 出力は `nimc`
echo ext      # 出力は `.html`
# 以下はすべて同じ文章を出力する
# `(dir: usr/local, name: nimc, ext: .html)`
echo baddir
echo badname
echo badext
```


###レファレンス型とポインタ型 [Reference and pointer types](http://nim-lang.org/docs/tut1.html#advanced-types-reference-and-pointer-types)
レファレンス（ほかのプログラミング言語のポインタ型に似ている）は多対一の関係を導入する方法である。
これはつまり、様々な参照がメモリ上の同じところを指し、同じ所を編集できることを示す。

Nimはトレースされる参照とトレースされない参照とを区別する。
トレースされない参照は*ポインタ*とも呼ばれる。
トレースされる参照はガーベジコレクトされるヒープ領域上のオブジェクトを指す。トレースされないオブジェクトはメモリ上のどこか別の場所に、手動で割り当てられるオブジェクト（たち）を指す。
したがってトレースされない参照は*安全でない*。
しかし、特定の低レベルな操作（例えばハードウェアへのアクセス）では、低レベルな参照が必要である。

トレースされた参照は`ref`というキーワードで宣言される。
トレースされない参照は`ptr`というキーワードで宣言される。

添え字が空っぽの`[]`はレファレンス型を逆参照することに使える。逆参照とはレファレンス型が指すものを取得することを意味する。

`.`（タプルやオブジェクトフィールドにアクセスする演算子）と`[]`（配列、文字列、シーケンスのインデックスの演算子）は参照型に対して、暗示的な逆参照の演算子として働く。

[reference.nim](https://ideone.com/rytkI1)

```nim
type
  Node = ref NodeObj
  NodeObj = object
    le, ri: Node
    data: int
var
  n: Node
new(n)
n.data = 9
#　n[].dataと書く必要はない。じつはn[].dataというのは強く非推奨である
```

トレースされるオブジェクトを新たに作るには、組み込みプロシージャの`new`を使う必要がある。
トレースされないメモリを扱うには、`alloc`、`dealloc`や`realloc`が使える。
[system](https://nim-lang.org/docs/system.html)モジュールのドキュメントに詳細が書いてある。

レファレンス型が何も指していない場合、`nil`の値を持つ。



###プロシージャ型 [Procedural type](http://nim-lang.org/docs/tut1.html#advanced-types-procedural-type)
プロシージャ型はプロシージャへの（多少、抽象的な）ポインタである。`nil`はプロシージャ型の変数に使える値である。
Nimはプロシージャ型を使うことで、関数型プログラミングのテクニックを使おうとしている。

[procesure_type.nim](https://ideone.com/iWKMrA)

```nim
proc echoItem(x: int) = echo x

proc forEach(action: proc (x: int)) =
  const
    data = [2, 3, 5, 7, 11]
  for d in items(data):
    action(d)

forEach(echoItem)
```

プロシージャ型に関するちょっとした問題があり、それは呼出規約が型の適合性に影響することだ。プロシージャ型は同じ呼出規約を持たないと適合しない。
様々な呼出規約は[マニュアル](https://nim-lang.org/docs/manual.html#types-procedural-type)
に書かれている。

### ディスティンクト型 [Distinct type](https://nim-lang.org/docs/tut1.html#advanced-types-distinct-type)

ディスティンクト型を使って"元の型のサブタイプである関係を暗示しない"型を新しく作ることができる。
ディスティンクト型の振る舞いはすべて**明示的に**定義しなくてはならない。
この作業の楽にするため、ディスティンクト型と元とした型は、一方からもう一方へ引用することが出来る。
例は[マニュアル](https://nim-lang.org/docs/manual.html#types-distinct-type)に書いてある。



##モジュール [Modules](http://nim-lang.org/docs/tut1.html#modules)
Nimではプログラムをモジュールの概念に基づいて分割することが出来る。
各モジュールはそれぞれのファイルを持つ。
モジュールは情報隠蔽と分割コンパイルを可能にする。
モジュールはimport文を用いることで別のモジュールの識別子を使うことが出来る。

アスタリスク（`*`）のしるしがつけられたトップレベルの識別子のみがほかのモジュールへエクスポートされる。

[export.nim](https://ideone.com/HQBPEr)

```nim
# モジュールA
var
  x*, y: int

proc `*` *(a, b: seq[int]): seq[int] =
  # 新しいシーケンスを割り当てる
  newSeq(result, len(a))
  # 二つのシーケンスを掛け合わせる
  for i in 0..len(a)-1: result[i] = a[i] * b[i]

when isMainModule:
  # 新しく作ったシーケンスのための``*``演算子を試す
  assert(@[1, 2, 3] * @[1, 2, 3] == @[1, 4, 9])
```

以上のプログラムでは`x`と`*`がエクスポートされるが、`y`はされない。

各モジュールは特別なマジック定数の`isMainModule`を持っている。これは、そのモジュール自体がコンパイルされるときはtrueである。上の例のように、テストを埋め込むのに便利である。

お互いに依存関係にあるモジュールを作るのは可能だが、強く非推奨である。これは一方のモジュールを、もう一方のモジュールなしで再利用できないからである。

モジュールをコンパイルするアルゴリズムは

- モジュール全体を通常通りコンパイルし、import文を再帰的にたどる
- もし循環があれば、すでに解析された識別子（エクスポートされた識別子）のみをインポートする。もし未知の識別子があれば、中止する

これは以下の例でよくわかる

（ideoneでの複数ファイルの使い方がわからないのでコードは略）

```nim
# モジュール A
type
  T1* = int  # モジュール A が``T1``型をエクスポートする
import B     # コンパイラがBを解析し始める

proc main() =
  var i = p(3) # Bがすでに完全に読み込まれているので動く

main()
```

```nim
# モジュール B
import A  # A はここでは解析されない。すでに解析されたAの識別子のみがインポートされる。

proc p*(x: A.T1): A.T1 =
  # T1がすでにAとのシンボルテーブルに追加されているため、動く
  result = x + 1
```

モジュールの識別子は`module.symbol`構文で*修飾*できる。
もし識別子が多義的であれば、*修飾*しなくてはならない。
ある識別子が多義的である、とは二つ以上のモジュールで定義されており、第三のモジュールにインポートされていることを指す。

```nim
# モジュールA
var x*: string
```
```nim
# モジュール B
var x*: int
```

```nim
# モジュール C
import A, B
write(stdout, x) # エラー：xが多義的 
write(stdout, A.x) # 問題なし: 修飾された

var x = 4
write(stdout, x) # 多義的でない: Cのxを用いる
```

しかし、このプロシージャやイテレータではこのルールが適用されない。
この場合、オーバーロードのルールが使われる。

```nim
# モジュールA
proc x*(a: int): string = $a
```

```nim
# モジュールB
proc x*(a: string): string = $a
```

```nim
# モジュールC
import A, B
write(stdout, x(3))   # エラーなし: A.x が呼び出された
write(stdout, x(""))  # エラーなし: B.x が呼び出された

proc x*(a: int): string = nil
write(stdout, x(3))   # 多義的: どっちの`x`が呼び出された?
```

###除外修飾子 [Excluding symbols](http://nim-lang.org/docs/tut1.html#modules-excluding-symbols)

通常の`import`文はすべてのエクスポートされた識別子をインポートする。
除外したい識別子を`except`で修飾して除外することで、インポートを制限できる。

```nim
import mymodule except y
```

###from文 [From statement](http://nim-lang.org/docs/tut1.html#modules-from-statement)
もう既に、エクスポートされたすべての識別子をインポートするような単純な`import`は学んだ。
代替法として、列挙した識別子のみをインポートするのが`from import`文だ。

```nim
from mymodule import x, y, z
```

`from`文は識別子の修飾を強制することが出来る。これにより識別子を使えるが修飾が必要となる。

```nim
from mymodule import x, y, z

x()           # xを修飾なしで使う
```

```nim
from mymodule import nil

mymodule.x()  # xにはモジュール名を前置した修飾が必要

x()           # ここxを修飾なしで使うのはコンパイルエラーを起こす
```

モジュール名は一般に、書くには長すぎるため、修飾の時のためにより短い別名を定義できる。

```nim
from mymodule as m import nil

m.x()         # mはmymoduleの別名
```



###include文 [Include statement](http://nim-lang.org/docs/tut1.html#modules-include-statement)
`include`文はモジュールのインポートとは根本的に異なることをする。ただ単にファイルの中身を含める。
`include`文は大きすぎるモジュールを複数ファイルの分けるのに使える。

```nim
include fileA, fileB, fileC
```

##パート2 [Part 2](http://nim-lang.org/docs/tut1.html#part-2)
ようやく基礎が終わり、次はNimが手続き型言語のための素敵な構文以外に何を提供しているか、見てみよう。[Part II](https://nim-lang.org/docs/tut2.html)

#訳注