Help us understand the problem. What is going on with this article?

Nimで地味に便利な関数とか

More than 1 year has passed since last update.

はじめに

この記事はNim Advent Calender 2018の9日目です。

大体Nimの文法は分かったのでそろそろなんか書いてみようかな、ぐらいの人向けのつもり。
基本的にLinuxかMacのターミナル環境での実行を想定しています。

環境

Ubuntu 18.04
Nim 0.19.0

知ってると地味に便利な関数たち

モジュールごとに紹介します。Standard Libraryのみ。

sequtils

applyIt, mapIt
配列に対して、中身をひとつづつit変数に代入して第二引数に与えられた処理をするテンプレート(関数を生成する、メタな関数)です。
apply, mapのシンタックスシュガーのようなものですが、構文がかなりシンプルになります。
applyItは引数の配列を操作、mapItは返り値として結果の配列を返します。
mapItの方は返り値の型が元の型に縛られないので便利。

ちなみにNimのmap系関数は中でループが動いているだけなので普通に速いです。

sample.nim
import sequtils
var
  seq1 = [1, 2, 3]

# string型にキャストする関数'$'
echo seq1.mapIt($it)  # -> ["1", "2", "3"]
seq1.applyIt(it * 3)
echo seq1             # -> [3, 6, 9]
# it変数を使用する必要はない
echo seq1.mapIt(5)    # -> [5, 5, 5]

strutils

(頻繁に使用するライブラリですが、これと言って便利な関数はない気がする...)
editDistanceでレーベンシュタイン距離を取得できます。
parseBoolはそれなりに緩い判定で文字列をboolに変換できるので、ユーザー入力を処理したい場合とかに便利かもしれない。
split系の関数は同名のイテレータが存在するので、そのままfor文に放り込めて便利かもしれない。
使ったことはないですがtokenizeイテレータとかも便利そうです。

algorithm

sortedByIt
割と面倒なtupleの配列のソートを楽にするテンプレート。

sample.nim
# 公式から引用
type
  Person = tuple[name: string, age: int]
var
  p1: Person = (name: "p1", age: 60)
  p2: Person = (name: "p2", age: 20)
  p3: Person = (name: "p3", age: 30)
  p4: Person = (name: "p4", age: 30)
  people = @[p1, p2, p4, p3]

echo people.sortedByIt(it.name) # -> name順に並べ替え

# SQLのORDER BYのように条件を複数つけることも可能、その場合条件をtupleで渡す
echo people.sortedByIt( (it.age, it.name) ) # -> age順に並び替えた後、ageが同じPersonの中でname順に並べ替え

math

なぜか言語に組み込まれていない、累乗演算子^が含まれています。
ただし第二引数に負の数や浮動小数点型を指定することができないので、その場合は同モジュール内のpow関数を使用しましょう(注: pow関数はpow関数でどちらの引数にもfloat型しか指定することができない)。

いろいろ試していて気づいたんですが、基数に負の値、指数に偶数を指定した場合の、返り値の正負が言語によって違うみたいです。
詳しく調べたら数学っぽい内容になってきたので諦めました。

rdstdin

readLineFromStdin関数は、特にインタプリタやREPLなど、ユーザからの入力を連続で処理するものを作るのに便利です。
readLine(stdin)と比べ、プロンプトを設定できたり、矢印キーやemacs(ターミナル)のキーバインドで移動できたり、履歴が出せたり、C-cやC-dのキャッチが楽だったりします。

while_read.nim
import rdstdin

var line: string

# プリミティブな実装
# いろいろ大変
while true:
  stdout.write("プロンプト")
  line = readLine(stdin)

# 便利な実装
while true:
  line = readLineFromStdin("プロンプト")

まとめ

便利にラッピングされているものはテンプレートに多いので、公式のprocをザッと見たら下の方にあるtemplateやiteraterを見てみるのもいいと思います。

0.19.0でstring型とseq型が型宣言のみで初期化されるようになって、謎のSIGSEGV: Illegal storage accessに悩まされることがなくなって幸せです。

mkanenobu
OCaml, Nim, TypeScript, React.js, React Nativeなど
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした