至高の言語、Nimを始めるエンジニアへ

**流行っていなくとも、良いものは良い。美しいものは美しい。**

![Nimro.png](https://qiita-image-store.s3.amazonaws.com/0/57005/4dfd89a6-c3f1-c026-769a-c5b09cf00f5d.png)

『Nimを触り始め(る|た)けどドキュメント少なすぎ！ なにから学べばいいかわからない！』
という人（過去の私）へ贈ります。

「このあたり知っておけば、言語理解が速いはず :kissing_heart: 」 って想いで書いています。
触り始めて間もない私なので粗があると思いますが、みなさんにとってNimへの良い入り口となれば幸いです:blush:

_ちなみに私はWeb系に偏っており、ポインタ？美味しいよねぇ といった具合です。_
_詳しい記事への導線を配置しているので、この記事はあくまでも最初のつまづき用の杖だと思ってください。_

# Nimの素敵ポイント
いきなり本題とずれますが、宣伝させてください。 :tired_face:

**Nim** とは
**美しくありながら**
**パフォーマンスがかなり高く**
**メタプログラミングに長けた**
コンパイル言語です。

```nim:美しく、そして速い言語、Nim
const
  fizzBuzz = "FizzBuzz\n"
  fizz     = "Fizz\n"
  buzz     = "Buzz\n"

var str = ""

for i in 1 .. 100:
  if   i mod 15 == 0: str.add(fizzBuzz)
  elif i mod  3 == 0: str.add(fizz)
  elif i mod  5 == 0: str.add(buzz)
  else:
    str.add($i)
    str.add("\n")

stdout.write(str)
```

_『じゃあ、何故流行ってないの？』_
その大きな原因は **ドキュメントの不足** だと思っています。
（公式というより、Qiitaとかブログとかの！）
みんなで盛り上げていけば輝く原石です。

こちらの記事も読んでいただけると、Nimの輪郭がはっきりすると思います。
[Nim言語感想&概説](https://qiita.com/snowlt23/items/f50ab84afeab9469e422)

# 環境作りや実行周り

anyenvにはまだ居ません。（2018/01/17 時点）
Nimのバージョン管理 :point_right: [choosenim](https://github.com/dom96/choosenim)

```shell:インストール（macOS）
brew install nim
```

公式サイトからのインストール :point_right: [https://nim-lang.org/install.html](https://nim-lang.org/install.html)

主流のライブラリマネージャーは [nimble](https://github.com/nim-lang/nimble) です。

エディタはVSCodeかKDevelop(IDE)でいいと思います。
[VisualStudioCodeによるNim開発環境](https://qiita.com/6in/items/78c3c8995567f2244a46)
[Aporia](https://github.com/nim-lang/Aporia)はちょっと使いづらい...。（AporiaはNimで書かれたIDE）

```shell:コンパイルと実行
nim c -r hello.nim
```

```shell:リリース向けコンパイル
nim c -d:release hello.nim
```

`-d:release`を付けないでコンパイルするとデバッグ情報が付加されるため、動作が遅くなります。

# コードの書き方／読み方
基本的な構文はこちらの記事を。
- [Syntax of Nim](https://gist.github.com/miyakogi/b1df00c8bc99927d9d0d)
- [Nim Tutorial Part Iを日本語訳してみた（前編）](https://qiita.com/KTakahiro1729/items/f4776f3a072c01f9086b)
- [Nim Tutorial Part Iを日本語訳してみた（後編）](https://qiita.com/KTakahiro1729/items/3f18811267bf4f8075d5#_reference-cbbfacf6fa955fc51b49)
- [【Nim】個人的逆引きリファレンス](http://flat-leon.hatenablog.com/entry/nim_howto)
最高！ほんと助かります :sob:

どんな関数があるの？ってときはソースコードを読むのがオススメです。
私は日本語ドキュメント依存のゆるふわエンジニア生活を送っていたために少々つらかったですが、関数内部の処理まで覗けるのは良いですね :crown:
私が最初のうちによく読んだのは [lib/system.nim](https://github.com/nim-lang/Nim/blob/master/lib/system.nim) です。

あとは公式ドキュメントの [Index](https://nim-lang.org/docs/theindex.html) を`⌘ + F`するとか :rolling_eyes:

## キャメル？ スネーク？
キャメルケース、スネークケースどちらでも書けます。たとえ宣言済みの変数であっても :flushed:
でも、公式ではキャメルケースが推奨されています。~~じゃあスネーク禁止にしたほうがよくない！？~~
[Nim Enhancement Proposal #1 - Standard Library Style Guide](https://nim-lang.org/docs/nep1.html)
UpperCamel(Pascal) ↔ lowerCamel はエラーになります。

```nim:キャメル
readLine(stdin)
```

```nim:スネーク
read_line(stdin)
```

```nim:フィーバー!!（動きます）
r_E_a_D_l_I_n_E(stdin)
```

## デバッグ
[`repr`](https://github.com/nim-lang/Nim/blob/master/lib/system.nim#L1586)関数で値の中身を確認することができます。
JavaScriptの`console.log`とか、PHPの`var_dump`みたいな感覚で使ってます。
ポインタの参照先やアドレスなども確認できます。

```nim:出力はechoとかで行う
echo repr(holyGrail)
```
デバッグ向きechoとして[`debugEcho`](https://github.com/nim-lang/Nim/blob/master/lib/system.nim#L2794)がありますが、
プロシージャ（関数）の副作用...？
コメント読んでも何を言ってるのかわかりませんでした :tired_face:
（デバッグ時にのみechoするのかな）

ステップ実行はこちらの記事を読んでいただけると。
[nimのデバッグ](https://qiita.com/6in/items/379bc1ba18241ddf5404)
（私は試してないです）

## 変数/定数の宣言

宣言は三種類あります。

**`const`**
定数です。コンパイル時に値がわかるものでないといけません。
例えば、コンソールから入力されるような値は代入できません。この場合は`let`を使います。

**`var`**
他言語でもよく見る、普通の変数です。

**`let`**
再代入が禁止された`var`です。コンパイル時に値が決まっている必要はありません。

_この項目は他の方もまとめられているのですが、本記事を読み進められるよう、一応書きました！
@2vgさん、アドバイスありがとうございました:v:_

## Stringへの型変換
型変換は様々ですが、Stringにできそうな大抵の型は`$`がサポートされていて、手前に付けると文字列になります。

```nim
var number = 42

echo "答えは" & $number & "です。"
```

`&`は文字列連結です。

[`echo`](https://github.com/nim-lang/Nim/blob/master/lib/system.nim#L2778)関数では内部的に`$`が使われる上に、複数の引数を受け付けるので、以下のようにも書けます。

```nim
var number = 42

echo "答えは", number, "です。"
```

## 関数（proc, プロシージャ）への引数渡し
第一引数を関数の手前に書いてメソッドチェーン風にしたり、カッコを省略できたりします。これ好き :relaxed:
[`write`](https://github.com/nim-lang/Nim/blob/master/lib/system.nim#L3064)関数を例に挙げます。

```nim:ノーマル
write(stdout, str)
```

```nim:チェーン
stdout.write(str)
```

```nim:カッコ省略
stdout.write str

write stdout, str
```

```nim
stdout.write"これもOK"
```

## ネスト
`let`や`var`等はネストでまとめることができます。

```nim:ノーマル
const wrong   = "ポピプテピック"
const correct = "ポプテピピック"
var message: string
```

```nim:ネスト
const
  wrong   = "ポピプテピック"
  correct = "ボブネミミッミ"
var
  message: string
```

また、Nimでは主に2スペースのインデントが使われます。NimとPythonを交互に書くと酔いますね :fearful:

## 破壊的な関数
Nimに限った話では無いですが、再代入が禁止されている `const` `let` に対して破壊的な（変数の内容を書き換える）関数を使うとエラーになります。

string型にstring型を追加する[`add`](https://github.com/nim-lang/Nim/blob/master/lib/system.nim#L1335)関数の例です。

```nim:第一引数はvar限定
proc add(x: var string, y: string)
```

```nim:OK
var cuteVoice = "piyo"

cuteVoice.add("piyopiyo")
```

```nim:エラー
let cuteVoice = "piyo"

cuteVoice.add("gieeeeeeeeeeee!!!")
```

# Nimの本
[コメント](#comment-f8d62afce9d7c37bcb4a)にて、Nimの本を教えていただきました。
公式サイトに載ってたのにガンスルーしてました... :rolling_eyes:
LiveBook形式ならブラウザで開くことで、Google翻訳できるみたいです！

:point_right: [Nim in Action](https://www.manning.com/books/nim-in-action)

_@6inさん、ありがとうございます :relaxed:_

# 頂いた質問への回答
## FizzBuzzのイミュータブルな解決法は？
現バージョンでforEachの実装が見当たらなかったため、このような書き方になるかと思います。
配列に足していく書き方をすると、パフォーマンスが結構落ちるかも。
Nimmerの先輩方！もっといい方法あれば、教えていただけると :pray:

```nim
import sequtils

proc fizzBuzz(i: int): string =
  if   i mod 15 == 0: "FizzBuzz"
  elif i mod  3 == 0: "Fizz"
  elif i mod  5 == 0: "Buzz"
  else: $i

for word in toSeq(1..100).map(fizzBuzz):
  echo word
```

↓ @biotist さんにイテレータ版を教えていただきました！ありがとうございます！

```nim
iterator fizzBuzz(max: int): string =
  for i in countup(1, max):
    yield if   i mod 15 == 0: "FizzBuzz"
          elif i mod  3 == 0: "Fizz"
          elif i mod  5 == 0: "Buzz"
          else: $i

for word in fizzBuzz 100:
  echo word
```

## パターンマッチはある？
`case`文はありますが、arrayやtupleなど、複数の値を抱えるものを同時に検査することはできません。（たぶん...）
ですので、FizzBuzzに使うと結構泥臭いことになります。

```nim
proc fizzBuzz(i: int): string =
  case i mod 15:
    of 3, 6, 9, 12: "Fizz"
    of 5, 10: "Buzz"
    of 0: "FizzBuzz"
    else: $i
```

改善が望まれます :innocent:
（これで洗練されている説もあります）

## string interpolation はある？
_string interpolation = 文字列補間_
strutils というライブラリで[`%`](https://github.com/nim-lang/Nim/blob/master/lib/pure/strutils.nim#L2351)を使って実現できます。

```nim
import strutils

echo "答えは $answer です。" % ["answer", $42]

# => 答えは 42 です。
```

~~文字列内での変数展開のような実装は見つけることができませんでした。~~
~~これもあるといいなぁって思います。~~

**Nim 0.18.0 でstrformatが追加されました :star2:**
[Nim 0.18.0のリリースまとめ #strformatモジュール](https://qiita.com/2vg/items/0e75b686800d0b27b5e9#strformat%E3%83%A2%E3%82%B8%E3%83%A5%E3%83%BC%E3%83%AB)
[Module strformat](https://nim-lang.org/docs/strformat.html)

```nim
import strformat

const name = "りがに"

echo "今日のごはんは？"
echo fmt"わぁい {name}{readLine(stdin)}すこ"
```

# おまけ
原型を保ったまま速度を詰めたFizzBuzz(100万回転)を置いておきます :japanese_goblin:
Nimのパフォーマンスの高さを体感していただければと思います。

```nim
var
  str = ""
  i = uint(0)

while uint(1_000_000) > i:
  i.inc
  case i mod 15
  of 3, 6, 9, 12:
    str.add("Fizz\n")
  of 5, 10:
    str.add("Buzz\n")
  of 0:
    str.add("FizzBuzz\n")
  else:
    str.add($i)
    str.add("\n")

stdout.write(str)
```

コンパイル時に全展開とかはナシで、もっと速いものがあれば教えてください！（懇願）

# おわりの言葉
記事最初の画像のマスコット（Nimro）は私の落書きなので、非公式です。~~流行って！~~

「最初の頃、このへんでハマったよ」みたいなものがあれば、教えてください :raised_hand:

また、Nimは[develブランチ](https://github.com/nim-lang/Nim/tree/devel)が活発で、将来この記事に書いてある幾らかは嘘っぱちになることも有り得ますので、お気を付けください :alien:
（嘘っぱちになったら ご指摘いただけると最高な気持ちです）

追記: NimroをSVG化したので置いておきます（Rejectされました:ghost:）

```xml
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 177.9 186">
  <style>
    .body { fill: #171921 }
    .eye,
    .mouth { fill: #fdfdfd }
    .iris { fill: #9a8700 }
    .tie,
    .crown { fill: #ffe952 }
    .jewelry.purple { fill: #bd93f9 }
    .jewelry.pink { fill: #ff79c6 }
    .jewelry.blue { fill: #6272a4 }
  </style>
  <path class="body" d="M28.9 72.5c0.1-2.3 4.3 1.5 16.3-3.8 6.2-2.7 16.4-10.5 20.7-17.6 8.7-14.3 18.3-23.9 42.1-25.5 19.1-1.3 36.7 9.4 43.8 22.3 6.6 11.9 10.2 21.2 14.8 27.1 5.7 7.2 13.2 4.3 10.8 9.1 -3 6.2-22.3 2.6-22.3 2.6 -5.9 30.6-9.8 47-33.7 65.1l1.1 22.5c0 1 0.8 1.8 1.7 1.9 3.5 0.5 11.6-0.3 10.6 3.7 -1.2 5.3-10.8 2.7-15.1 2.4 -1.1-0.1-2.1-0.9-2.4-2 -1.6-6.7-4.3-24.5-4.3-24.5 -12.4 5-22.1 6.4-34.2 4.8l2.6 19.1c6.1 0.1 11.9-0.2 10.6 4.1 -1.1 3.5-8.9 1.9-13.2 1.5 -1.1-0.1-2.5-1.3-2.7-2.4 -0.8-4.1-5.9-24.1-5.9-24.1 -11.6-5.4-20.5-12.5-26.8-24.6 0 0-15.9-2.5-23.1-6.6 -8.5-4.9-12.2-11.2-12.2-11.2 -8.5 0.3-10.3-7.6-6.2-11.3 4.7-4.3 13.9 0.1 9.6 8.5 0 0 4.6 5 12.7 7.8 9.8 3.4 18.7 3.4 18.7 3.4 1.8-11.8 6.7-30.2 12.5-43.2 0 0-9.3 0.1-15-0.4C29.6 80.2 28.8 74.4 28.9 72.5z"/>
  <path class="eye" d="M98.8 55.4c-0.4 4.3-4.2 7.1-8.2 7.8 -4.7 0.8-7.6-3.3-7.6-7.7s3.5-8 7.9-8.2C95.3 47 99.3 50.2 98.8 55.4z"/>
  <path class="iris" d="M96 55.3c-0.2 2.5-2.4 4.1-4.7 4.5 -2.7 0.5-4.4-1.9-4.4-4.4 0-2.5 2-4.6 4.6-4.7C93.9 50.5 96.2 52.4 96 55.3z"/>
  <path class="eye" d="M137.9 53.9c0 5-3.5 6.7-7.8 6.1 -4.6-0.7-8.2-2.6-8.2-7.3s2.9-8.2 8.4-8.2C135.2 44.5 137.9 48.7 137.9 53.9z"/>
  <path class="iris" d="M134.5 53.5c0 3-2.1 4-4.7 3.7 -2.8-0.4-4.9-1.6-4.9-4.4 0-2.8 1.7-4.9 5-4.9C132.8 47.9 134.5 50.4 134.5 53.5z"/>
  <path class="mouth" d="M104.5 65.8c-3.3 3.7-2 10.5 2.4 11.5 5.3 1.2 10.4-4.5 10.4-4.5s3.5 4.1 8.2 3.2c3.6-0.7 5.5-3.7 4.7-7.2 0 0-1.2 6.7-7.2 5.5 -3.9-0.8-4.3-5.2-4.6-6.9 0-0.2-0.3-0.3-0.5-0.1 -1.2 2-4.4 8.2-9.3 7.1C102.3 72.9 104.5 65.8 104.5 65.8z"/>
  <path class="tie" d="M109.8 101.4c0.8 1 5.7-1.3 7.3-2.2 0.3-0.2 0.7-0.1 0.9 0.1 1.2 0.9 4.3 3.2 5.9 2.7 2-0.6 4.7-9.2 2.6-9 -1.5 0.2-5.8 2.1-7.4 2.8 -0.4 0.2-0.9 0.2-1.3 0 -2.1-0.9-9-3.5-9.4-2C107.9 96 109.2 100.5 109.8 101.4z"/>
  <path class="crown" d="M65.8 14.3c-0.6-1.4 0.7-3 2.2-2.6l13.9 3.7c0.9 0.3 2 0.1 2.6-0.7l9.7-9.8c1-1.2 2.6-1.6 4-1.1l11.8 5.7c0.7 0.2 1.5 0.1 2.1-0.3l14.3-9c1-0.5 2.1 0.3 1.9 1.3l-3.9 25.9c-12.7 8.4-32 11.8-48.7 10.6L65.8 14.3z"/>
  <circle class="jewelry purple" cx="77.5" cy="21.8" r="2.4"/>
  <circle class="jewelry pink" cx="98.4" cy="17.1" r="2.4"/>
  <circle class="jewelry blue" cx="119.6" cy="14" r="2.4"/>
</svg>
```

**[雑感]**
トライキャッチ プリキュア