Haskellで作るCLI matsubara0507氏：「HaskellでCLI」というタイトルでお話しします。とくに自己紹介スライドとかはないんですけど、一応僕は職業Haskellerではなく、趣味でHaskellをたしなむ程度の人間なので、あまり難しいことは聞かないでください。 （会場笑） まだ僕は新卒でして。ここ半年ぐらいはHaskellとぜんぜん違う言語を使っていて、本当に趣味でちょこっとずつしかやってないから、最近のことはよくわからないので、とくに最近のことは聞かないでください（笑）。 本題。今回はみなさん、「これからHaskell触ってみたいな」という人が多いと思っているんですが、一方でHaskell自体が初めてのプログラミング言語だという人はほぼいないと思うんですけど、仮にHaskellを新しくプログラミング言語として学んだ場合、みなさんは何をしますか？ たぶんみなさん、コマンドラインを作ると思うんですよ。いきなりGUIを試すという猛者がいるかもしれないんですけど、ひととおり構文を学んだら、普通は簡単なターミナルのコマンドを叩いて、引数もらって、「あ、なんかいいぞ」みたいなことをやると思うんですよね。 今回はそれについてのお話をしたいと思います。とはいえ、あんまり入門書には書いてない、少しマニアックな話が多いんですけど、したいと思います。 1つ目が、「コマンドの話する」って言ってるんだから、「コマンドライン引数をHaskellでどうやって扱うか？」っていう話をします。 Haskellでコマンドライン引数を扱うのは、この3つ以外にも実はたくさんあるんですけど、僕がだいたい使うのはこの3つなので、この3つを紹介します。 1つ目が“getArgs”っていう標準のライブラリにある関数です。 Haskell自体をあんまり書いたことがない人が多いかもしれないんですけど。Haskellは“main”っていう関数からコマンドとか実行ファイルを作ると実行されるんですけど、そのなかで“getArgs”っていう関数を呼びます。 そうすると、左側にある“args”っていうところに、できたコマンドの名前の後に続くようなコマンドライン引数のところが、全部入ってきます。String型っていう文字列型の……、この“[]”は線形リストです。厳密にはぜんぜん違うんですけど、他の言語で言う「配列」とか、そういう認識だと思ってください。それが入ってきます。 “head args”ってしてるのは、1つ目を取ってきて、「Hi, 〇〇」みたいに出力するっていうのをやってます。たぶん入門書とかだと、まず“getLine”をして、標準入力を受け取るみたいにやると思うんですけど、それと同じような感覚で扱えます。 ただ、これは単純にコマンドライン以降の文字列を空白区切りで引っ張ってくるだけなんですよ。実際、リッチなコマンドを作りたいと思ったときは、「もう少しオプションのところをいい感じに扱いたいな」っていう野心が芽生えてくると思うんですけど、そうなってくると、さっきのではきついと。 そのためのものとして、標準で用意されているものに“GetOpt”というものがあります。 これは“getArgs”で得た文字列を与えて、いい感じに型にしてくれます。Haskell、なんとなく今日1日の話を聞いていて、みんな、「いい感じに型にして扱いたいんだな」っていうのがわかってると思うんですけど、そんな感じのことをしてくれます。 この1引数目の“ArgOrder”っていうのは、オプションでもなんでもないものをどうやって扱うかっていうだけで。2引数目の“OptDescr”っていうやつが、いい感じの型にしてくれるやつですね。この“a”って書いてあるところが、そのいい感じにしてほしい型を明示的に与えます。3引数目が、さっきの“getArgs”のやつですね。 返り値としては、3つ組のタプルで返ってくるんですけど、実際のパースできた型と、オプションの型と、それ以外とエラーで返ってきます。細かい説明は割愛します。 実際の使用例としては、この“data Flag”ってやつがいい感じにしてほしい型ですね。 よくある“Verbose”とか“Version”とかっていうのを定義してます。一番下の“options”っていうのが、そのパースの仕方を簡単に定義しています。なんとなく“v”と“verbose”で“Verbose”になって、“V”と“version”で“Version”になるみたいな感じです。それで、さっき“getArgs”で取ってきたものを、さっきの“GetOpt”関数に与えている、というような感じです。

RIOライブラリ 今回紹介するのは、このなかでもRIOと呼ばれるやつで、僕が愛用してるからというだけなんですけど、「本当にそれが一番いいか？」って言われると、たぶんそんなこともないので、みなさんいろいろ使って、自分で良し悪しを判断してください。すいません（笑）。 これは何かっていうと、stack……。ちょくちょく出てきている、午前も使ったビルドツールですね。stackを開発してるチームが開発している、Alt.Preludeです。実際、最近このRIOに変わったのかな、たぶん変わってるはず。彼らのベストプラクティスを詰め込んでいます。 例えば大域環境というか、大域な変数を扱いたいときとか、あと、Haskellってくると、だいたい「ログできないんでしょ？」って言われるロガーとか、あとエラーハンドリングのあたりとかというベストプラクティスをまとめたものです。 さらによく使うライブラリが、もうすでにラッパーとして組み込まれています。このあたりは「どうせみんなよく使う」というか、Haskellのビルド、cabalとかstackを使うとこれらが全部インポートされるみたいなやつが、もうすでに入っています。 例えばRIOの使用例、これは実際に最近作ったやつのコマンドの一部なんですけど。 これは何かっていうと、MediumっていうQiitaの海外版みたいなやつがあるじゃないですか。あれって残念なことにマークダウンが使えなくて、マークダウンに汚染された人間にとっては、ちょっとそれ、扱いにくいんですよね。 なんですけど、なぜかMediumのAPIからはマークダウンを送信できるという謎機能があって。 （会場笑） 12月から始まるみんな大好きアドベントカレンダーに向けて、どうしてもMediumに投稿しなきゃいけないんだけど、「マークダウンを使いたい」という要望のためにHaskellで書いたツールの一部です。 なんで、“MEDIUM_TOKEN”とかって書いてあるんですけど、この上の“run”っていうところがRIOのボイラーテンプレートみたいなもので、こんなふうに書くと、この下の“RIO Env （）”みたいなところでは、自由にロガーとか大域変数とかにアクセスができるという、謎な状態になってます、細かくはとくに話さないんですけど。だいたいこの“Env”にいろんなものが詰め込まれていて。 例えば“logDebug “Run cmd : call me api””とかって書いてあるみたいに、これをしとくと、ロガーがデバッグ時に表示してくれる、みたいな。で、“API get me token”っていうのは、普通のIOですね。これでMediumのMe APIを叩くぐらいのイメージなんですけど、これは単純にユーザーの情報を取ってくるだけのAPIですね。“logDebug”とかをしてくれる。“logInfo”で“Hi hoge !!”を出力してくれるみたいな感じです。 実際の出力例なんですけど、試しに……。 ここで“me”とかって打つと、さっきのやつが出てきますね。 それで、“verbose option”……、“v”でいけるのか、こんなふうにデバッグが出てきて。 これはRIOのデバッグの仕様そのままなので、わざわざ僕が何かしたわけでもないです。そんな感じです。

Stack Template 最後のテーマなんですけど、「Stack Template」っていう話をします。 「Stackとは何ぞや？」っていう話は、たぶんもういいと思うんですけど、Haskellのビルドツールで、ここ5、6年前ぐらいに出たやつですかね。それまでは、検索すればたぶんいっぱい出てくる「Cabal Hell」という地獄に悩まされていたと思うんですが、これのおかげでだいぶ初心者の導入のしやすさが上がったかと思います。 処理系自体は、Haskellとか言ってるけどGHCです。プロジェクト内の各パッケージのバージョン管理とかをしてくれます。他にもDockerをいい感じで扱ってくれたりとか、いろんな機能があるんですけど、RubyのBundleとか、Scalaの sbtと同じだと思ってくれて差し支えないと思います。 だいたいこの“stack new sample”で、一番右側“hoge-template”っていうのは、“new”したときに生成されるファイルのテンプレートを与えています。“sample”なのに、“sample-project”に“cd”してる。まあ、いいや。ミスです。それで、……“stack build”とかしてあげるとビルドが走って、“stack exec – application”とかってすると、できあがった実行ファイルを実行できる、みたいな感じです。 何回も何回も“stack new”するとわかってくると思うんですけど、“stack new”の後にやることってだいたい一緒で、推しパッケージをとりあえずDependencyに書いて……（笑）。 （会場笑） それで自分のところにそのGitHubのアカウントを足して……、みたいなことをやるんですよね。そういった何回も同じことをやるのを解決するために、オレオレテンプレートを作ることができます。これは最初からできてたんですけど。 例えばこういうふうなやつですね。 Haskellって固有拡張子がだいぶ好きなんですけど、hsfilesっていう、テンプレートでこういうふうに書くと、どう見てもHaskell専用の拡張子で。 例えば“package.yaml”っていうのは、Stackでのパッケージの指定の仕方なんですけど。オレオレ。大好きなDependencyというか、依存パッケージをこういうふうにあらかじめ書いておくとか、どうせインポートするんだから、最初のmainのところにもう書いておくとか、みたいなことができるようになります。 いままではそれをローカルに置いて、それを参照するぐらいしかできなかったんですけど、最近のアップデートで、GitHubとか、GitLabとか、BitBucketとかに置いたものが取ってこれるようになりました。こんな感じですね“stack new github :自分のGitHub名”に、そこに置いてあるhsfilesを指定してあげます。 作り方の詳しいところはこの記事を参照してもらえばいいんですけど。これは固定なんですけど、自分のところにstack tplsって呼ばれる、このリポジトリ名で1個処理を作って、なんちゃらhsfilesをトップのところに置いてあげると、さっきのやり方でアクセスできるようになります。