エフアンダーバー

個人開発の記録

PureScript 入門 のそのまえ

QiitaでPureScriptを始めるのに苦戦している記事を読んで、 自分もこの前すごく苦労したことを思い出したので、 まだ感覚が残っているうちにいろいろ書いておくことにしました。

PureScriptの紹介が目的ではないので、 「PureScriptとは何か」とか「どんなコードを書くか」みたいな話は特にしません。 PureScriptを学ぶ上で知っておくと役に立つかもしれない知識について雑多に書くだけです。

PureScriptを始めるその前に

PureScriptは比較的新しい言語で、かつ今のところ非常にマイナーな言語です。 そのため、現在資料がとても乏しく、いくらかき集めても、 関数型言語を何も知らない人間が理解するのは困難な状況です。

そこで、まず最初にやるべきはPureScriptの類似言語を学ぶことだと思います。 遠回りに感じるかもしれませんが、おそらくこちらの方が近道です。 私はいきなりPureScriptを学び始めて一度挫折しましたが、 類似言語を学んだ後にもう一度チャレンジしたところ、割とすんなりと理解できました。

学ぶのにおすすめの類似言語はElmとHaskellです。 どちらか、ではなく、Elm -> Haskellの順に勉強するのがいいと思います。

Elmは純粋関数型言語の難しい部分をばっさりと切り捨てたような言語で、 関数型言語のスタイルを学ぶにはうってつけの言語です。 公式のドキュメントが非常に読みやすいので、これに目を通すだけで十分だと思います。 時間を節約したいなら、The Elm Architecture (TEA)について学ぶだけでもいいかもしれません。 純粋関数型言語における副作用の扱いについて理解できると思います。 不名誉なことに、「2019年にわざわざ学ばなくてもいいプログラミング言語」で1位になってしまいましたが、 個人的にはプログラマが最も学ぶべき言語だと思っています *1

HaskellはPureScriptやElmの元となった言語ですね。 というか、PureScriptに至っては八割方Haskellそのままです。 PureScriptを書く上で学んで無駄になる部分はほとんどありません。 Haskellは歴史の長い言語なので資料は豊富ですが、 その分古い情報や発展的すぎる情報などのノイズが多いので、 内容が整理されている書籍で学ぶのがいいと思います。

有名なものが二つあって、ひとつは「すごいHaskellたのしく学ぼう!」という本で、通称『すごいH本』です。 自分はこれで勉強しました。 出版日からして若干の古さはありますが、最終目的がPureScriptであるならばほぼ問題にならないと思います。 とにかく非常に読みやすい本です。 実は私はHaskellについては本当にこの本を読んだだけで、 一行もコードを書いていませんが、 それでもPureScriptを学ぶ際の理解度に雲泥の差がありました。 気楽にやりたい人にはおすすめです。

もうひとつの有名な本は「プログラミングHaskell 第2版」です。 私が勉強を始めた数か月前の時点では、まだ第2版の翻訳は出版されておらず、 初版は古くなっていたので避けたのですが、名著との噂です。 原本もさることながら、 訳者の方もHaskellその他の話題でよくヒットするブログの著者なので、 信用していいかと思います。

PureScriptを学ぶためにまず別の言語を学べ、と言われると「えっ……」となるかもしれませんが、 おそらく思っているほど無駄な学びはありませんし、 必要ない部分はサクッと飛ばせばいいだけなので、それほど時間もかかりません。 よくわからないものを試行錯誤でなんとかしようとする方が遥かに時間の無駄です。

PureScriptの変遷

PureScriptはまだ正式リリースされていない言語です。 そのため、仕様その他がガンガン変わります。

古くなってしまった資料を見分けるために、どんな変化があったか知っておくことは重要です。 ここではそれらについて簡単に書いておきます。

覚えておくべき大きな変化は次の二つです。

  • EffからEffectへの変更
  • パッケージマネージャの変化

EffからEffect

PureScript 0.12 から外部への副作用を表す型がEffからEffectへと変更されました。

元々PureScriptでは、HaskellのIOに相当する型としてEffという型を使用していました。 この型では、rowという型の記述機能を使って、forall eff. Eff (console :: CONSOLE | eff) Unitのように、 どのような副作用なのかということまでも型の一部として記述していました(この例ではコンソール出力)。 どんな副作用を起こすのかというのは確かに重要で、 型によってそれを判別できるのが有用であることは間違いないのですが、 見ての通り記述が煩雑で、起こす副作用の種類が増えてくると非常に長い記述が必要となってきます。

そこで、この副作用の種類が必要かどうかのアンケートをとったところ、「いらない」ということになり、 すべての公式ライブラリ*2Effは新しいEffectへと書き換えられ、前述の型はEffect Unitというシンプルな記述になりました。

詳細はこちらの記事を参照してください。

パッケージマネージャの変化

PureScriptでは元々Bowerをパッケージマネージャとして使っていました。 しかし、Web業界ではnpmやyarnが一般的となり、Bowerは廃れゆく存在となりました。 一方で、PureScriptではバージョン管理周りでnpmを使いたくない理由があり、npmへの移行を渋っていました。

そこで、PureScript専用のパッケージマネージャをつくろう、ということになり、 psc-packageというパッケージマネージャの開発が始まりました。

そうして、徐々にpsc-packageに移行していくかと思われた頃に、 今度はspagoというパッケージマネージャが現れます。 これが非常によくできていたために、現在これがデファクトスタンダードとなりつつあります。

PureScriptの開発環境

PureScriptの開発に当たってとりあえず必要なツールは次の三つです。

  • purescript
    • PureScriptコンパイラのnpmパッケージ
  • spago
    • PureScriptパッケージマネージャのnpmパッケージ
  • PureScript IDE
    • PureScript開発用のエディタ拡張 (VSCode他)

purescript

PureScriptコンパイラはnpmパッケージとして提供されています。

次のコマンドでインストールします。

npm install -g purescript

もちろんグローバルインストールでなくても構いません。

正しくインストールされていればpursコマンドが使えるはずです。 ただし、基本的な操作はすべてspagoを介して行うことになるので、 直接このコマンドを使うことはほとんどないと思います。

spago

spagoもnpmパッケージとして提供されているため、次のコマンドでインストールします。

npm install -g spago

もちろんグローバルインストールでなくても構いませんが、 PureScriptコンパイラに依存しているのでそちらに合わせた方がいいと思います。

正しくインストールされていれば、spagoコマンドが使えるはずです。

基本コマンド

詳しい使い方はヘルプやspagoのREADMEを読むのがいいと思いますが一応概要だけ。

プロジェクトの作成には空のディレクトリを作成して、その中で次のコマンドを打ちます。

spago init

すると、

project
│  .gitignore
│  packages.dhall
│  spago.dhall
├─src
│     Main.purs
└─test
       Main.purs

という構成になるのでsrc/Main.pursにコードを書いていきます。

コードを書き終えたら、次のコマンドでビルドします。

spago build

ビルドは単にPureScriptをJavaScriptに変換するだけなので、 ひとつのファイルにバンドルしたいときには次のコマンドを使います。

spago bundle-app

何かライブラリをインストールしたい場合には、次のコマンドです。

spago install package_name

package_nameの部分は対象パッケージ名に置き換えてください。 パッケージ名を検索するとpurescript-というプリフィックスが付いているかもしれませんが、 これは省略して記述します。

Dhall

spagoプロジェクトには.dhallという拡張子の設定ファイルがあります。 これはDhall(ドール)というデータ記述言語によって書かれているファイルです。

DhallはHaskellライクな文法で記述する、 静的な型検査や簡単な計算機能を備えるデータ記述言語です。 「それってほぼプログラミング言語なのでは?」と思うかもしれませんが、 チューリング完全でないという特徴を持っていて、 複雑な計算ができない代わりに、安全に終了することを保証しているそうです。

Dhallの注意点として、Dhallは別のDhallファイルをインポートする機能を有しているので、 そのキャッシュの保存場所が必要です。 保存場所は${XDG_CACHE_HOME}あるいは${HOME}/.cacheの内部になります。 以前はWindowsにおいてこれらの環境変数を指定する必要があったのですが、 この記事を書くにあたり確認したところ、${LOCALAPPDATA}を対象に追加するPRがマージされていたので、 おそらく今後は必要ないものと思われます。

spagoに含まれるDhallファイルは、spago.dhallとpackages.dhallの二つです。 spago.dhallはパッケージ自体の情報を保持していて、内容は中身をみればすぐわかります。 packages.dhallにはインストールする外部パッケージはどこにあるのかという情報が記述されています。 中にはなにやら色々書いてありますが、ほとんどは書き方を説明したコメントで、 設定自体は最後のほんの数行だけです。

package-sets

packages.dhallの最後の方にはこんな感じの記述があります。

let upstream = https://github.com/purescript/package-sets/.../packages.dhall sha256: ...

これはupstreamの値をこのURLの示すDhallファイルの評価値とする (sha256:以降はファイルのハッシュ値)という意味で、 この行がspago installでどんなパッケージをインストールできるのかを決定しています。

URLはpackage-setsというリポジトリ内のファイルを指していて、 対象のDhallファイルを順に辿っていくと、最終的に次のような記述が並ぶファイルに到達します。

console =
    { dependencies =
        [ "effect", "prelude" ]
    , repo =
        "https://github.com/purescript/purescript-console.git"
    , version =
        "v4.2.0"
    }

これがインストール可能なパッケージとそのソースコードの場所を教えてくれているわけです。

もし、自分のつくったライブラリを皆に使ってもらいたいのであれば、 package-setsにPRを送って、自分のパッケージ情報を登録してもらえばいいそうです (やったことはないので詳しいことは知りません)。

このライブラリの指定方法を見ればわかるように、 基本的にPureScriptではパッケージ毎にバージョンを上げるのではなく、 このpackage-setsのバージョンを上げるようです。

spago upgrade-set

packages.dhallのoverridesadditionsを書き換えれば、 細かいバージョンの管理やローカルプロジェクトの参照なんかも可能です。

PureScript IDE

PureScriptのコンパイラにはpsc-ideというIDE用のサーバプログラムが付属していて、 各エディタにプラグインを入れることで、その機能が利用できるようになっています。 例えばVS Codeでは、PureScript IDEというそのまんまの名前の拡張機能が提供されています。

開発に必要なサポート機能がいろいろと入るので、基本的に入れておいて損はないと思います。

PureScriptの学習

最後にPureScriptの学習方法について少しだけ。

PureScriptをどう学ぶべきかについて、残念ながら現時点ではそれほど決定的な方法はないと思います。 これさえ読んでおけば大丈夫というものを私は知りません。 なので、自分が学ぶのに役立ったと感じた資料の紹介だけしておこうと思います。

私がPureScriptの学習の際に参照した主な資料は次の通りです。

一番上はパーマリンクなので情報の更新に注意してください。

PureScript Language Reference

PureScript公式(?)の言語リファレンスです。

びっくりするほどあっさりとしているので、これを読めばコードを書けるというものではありませんが、 何ができるのか一通り確認できる手軽な資料です。

重要なのは一番下の"Differences from Haskell"の項で、Haskellとの違いが書かれています。 Haskellを知っているのであれば、これを読むだけである程度書けるような気分になります(実際に書けるかどうかは知らない)。

PureScript By Example

一応これがPureScript公式のチュートリアル……ということになるのだと思います。

PureScriptについて非常によく説明されているいい資料なのですが、 いかんせんPureScriptのバージョンが古いため、サンプルがまともに動きません。

とはいえ、PureScriptの機能自体がそれほど大きく変化してきたわけではないため、 バージョンが古いということを念頭に入れて読めば、まだまだ役に立つ資料です。 Haskellを学んだ上で流し読みして、PureScript特有の部分だけ拾うのをおすすめします。 その際、前述したPureScriptの変遷を頭に入れておくと、無駄な部分も飛ばせると思います。

「実例によるPureScript」の題で邦訳してくれた方がいるため、日本語でも読めます。

Pursuit

PursuitはPureScriptパッケージのAPIドキュメントを参照・検索できるサイトです。

まずはこのサイトで、自動的にインポートされるPrimモジュールや、 よく使う機能がまとめられたPreludeモジュールの内容を確認してみるのがいいと思います。 結構しっかりとドキュメントが記述されていることが多い印象です。

Pursuitで特に便利なのが、APIのソースコードを参照できる機能で、 これにより公式パッケージのAPIの実装方法なんかも確認できるので、 コードの書き方を学ぶのには重宝します。

自分はある処理を書きたいけど書き方がわからないという場合に、

  1. Haskellで同等の処理をするのに必要なAPIをWebで検索する
  2. そのAPIをPursuitで検索する
  3. 出てきたAPIのドキュメントやソースコードを読む

ということをよくやっていました。

私のように下地もなしにPureScriptを始めたような人間にはおすすめの方法です。

Halogen

HalogenはPureScriptの有名なUIライブラリです。

Halogenが特別PureScriptの学習に向いているというわけではないのですが、 何か良質なサンプルがあるフレームワークでものをつくるというのはどんな言語の学習でも役立つもので、 Halogenはその選択肢のひとつとしていいんじゃないかという話です。

まあ、もっと言えば、私がものつくるのに使ったのがHalogenだったというだけなんですが……。

ReactやElmみたいなアーキテクチャを想像していると、 少し違って戸惑いますが、 モナドによる副作用の扱いなんかを学ぶにはいいフレームワークだと思います。

PureScriptでアプリをつくった時の記事

www.f-sp.com

おわりに

Qiitaの記事を読んでから、思い立ったが吉日とばかりに一気に書いたので、結構適当なこと書いたような気がします。 なんか意味わからんこと言っていたら「初心者がバカ言ってら」と笑い飛ばしといてください。 ただ嘘を言っていたら伝播する前に教えてもらえると幸いです。

特に語りたいこともないので、以上。



執筆時のPureScriptのバージョン:0.13.3

*1:そもそもランキングは『仕事をとる上で』という文脈なのでその意味では概ね同意ですが

*2:「標準ライブラリ」と呼んでいいものか怪しいので「公式ライブラリ」としておきます