この記事は (bouzuya) PureScript Advent Calendar 2016 の 4 日目。 (bouzuya) PureScript Advent Calendar 2016 は bouzuya の PureScript 学習の記録だ。
- ← 3 日目『 PureScript の build tool
pulp
を動かしてみる - Qiita 』 - → 5 日目『 PureScript by Example 1 章を読む - Qiita 』
概要
4 日目にして、いまさらだけど Getting Started with PureScript を見る。見ながら、 psci
の残りのコマンドを見ていく。
公式 の LEARN を開いたらリンクがあったので、漏れを確認する意味で見ていく。
準備
環境構築まわりの次の手順は 1 / 2 / 3 で触れたのでスルー。
$ npm i -g purescript pulp bower
$ pulp init
$ pulp build
$ pulp test
ここまでは前回までとほとんど同じなので、環境は前回のものを使用する。念のため再掲しておくと次のような感じ。
$ mkdir project3
$ cd project3/
$ npm init -y
$ npm install -D bower pulp purescript
$ \vi package.json # scripts に `pulp` 関連のものを追加
$ npm run pulp:init
$ git init
$ git commit -m 'initial commit'
bower install
Getting Started に従って purescript-lists#3.2.1
をインストールする。元ページではバージョン指定はないが、動きが変わるとややこしいのでここでは明示的に指定する。
$ $(npm bin)/bower install -S purescript-lists\#\^3.2.1
また上記 purescript-lists#3.2.1
のほかに pulp init
を実行しているので、次のコマンドが合わせて実行された扱いになる ので、いくつかのパッケージが依存関係に追加される。
bower install --save purescript-lists purescript-console
bower install --save-dev purescript-psci-support
バージョン指定はないのだけど、今回は結果的に purescript-prelude#2.1.0
/ purescript-console#2.0.0
/ purescript-psci-support#2.0.0
が依存関係に入り、 bower.json
は次のようになった。
$ cat bower.json
{
"name": "project3",
"ignore": [
"**/.*",
"node_modules",
"bower_components",
"output"
],
"dependencies": {
"purescript-prelude": "^2.1.0",
"purescript-console": "^2.0.0",
"purescript-lists": "^3.2.1"
},
"devDependencies": {
"purescript-psci-support": "^2.0.0"
}
}
Pursuit:
purescript-lists
は Data.List
などのモジュールを提供するようだ。
pulp psci
で import
やコマンドをためす
import Prelude
と (psci) :type
とりあえず pulp psci
をして、import Prelude
してみる。
$ npm run pulp:psci
> project3@1.0.0 pulp:psci /Users/bouzuya/project3
> pulp psci
PSCi, version 0.10.2
Type :? for help
> import Prelude
> :type map
forall a b f. (Functor f) => (a -> b) -> f a -> f b
> :t map
forall a b f. (Functor f) => (a -> b) -> f a -> f b
前回もそうだけど :type
は :t
で良い。
次は import Data.List
。
> import Data.List
> :type zip
forall a b. List a -> List b -> List (Tuple a b)
Getting Started によると Tab
で補完が効くようだ。import
まで打ったときで候補が変わるので、文脈も考慮されているようだ。
(psci) :show import
ここは Getting Started にないのだけど、 :show import
を試してみる。import
されたモジュールを表示できるようだ。
> :show import
import Data.List
import Prelude
> import Data.List
> :show import
import Data.List
import Data.List
import Prelude
(psci) :show loaded
ついでに :show loaded
を試す。こちらは読み込まれたモジュールを表示できるようだ。
> :show loaded
Control.Alt
(中略)
予想以上に表示された。
(psci) :reset
次は :reset
で読み込まれたモジュールをリセットしてみる。
> :reset
> :show import
> import Prelude
> :show import
import Prelude
> :reset
> :show import
>
なるほど、たしかに消える。
(psci) :kind
:kind
。型の種類を表示する。あまり理解できていない。型変数の数 (?) みたいな認識で居る。
> import Data.List
> :kind List
* -> *
> :kind (List Int)
*
(psci) :browse
:browse
。モジュールに含まれる関数を表示する。
> :browse Data.List
(中略)
zipWith :: forall a b c. (a -> b -> c) -> List a -> List b -> List c
zipWithA :: forall m a b c. (Applicative m) => (a -> b -> m c) -> List a -> List b -> m
(List c)
(psci) :paste
:paste
。複数行の場合に使えるっぽい。
> import Prelude
> :paste
… 1
… +
… 2
3
>
Getting Started の続き
大きく脱線したけど、ここから戻る。
$ npm run pulp:psci
> project3@1.0.0 pulp:psci /Users/bouzuya/project3
> pulp psci
PSCi, version 0.10.2
Type :? for help
> import Prelude ((==), (||), mod)
> import Data.List (filter, range)
> import Data.Foldable (sum)
> let ns = range 0 999
> let multiples = filter (\n -> mod n 3 == 0 || mod n 5 == 0) ns
> :type multiples
List Int
> sum multiples
233168
> :quit
See ya!
説明なんて冗長な感じもするけど……
-
range
で 0 以上 999 以下の整数の List をつくり、変数ns
を束縛する -
ns
の各要素に対して、mod
で 3 の剰余をとって 0 、または 5 の剰余をとって 0 のみをfilter
で選択する -
sum
でそれらの要素を合計する
という感じ。
JavaScript と文法事項を比較すると (差分が大きすぎる気もするけど) …… 、ここでは関数の呼び出しに ()
は要らないとか \x -> x
が x => x
くらいかな?あとは雰囲気で読めるはず……。
src/Euler.purs
Getting Started では src/Euler.purs
を作成し、それを import Euler
で読み込んでいる。
src/Euler.purs
:
module Euler(answer) where
import Prelude ((==), (||), mod)
import Data.List (filter, range)
import Data.Foldable (sum)
ns = range 0 999
multiples = filter (\n -> mod n 3 == 0 || mod n 5 == 0) ns
answer = sum multiples
psci
とは違い、 let
は不要だ。
ぼくの趣味で import する関数を限定し、 module 外に export するものを answer
に限定した。このあたりは次の Language Guide を参照すると良い。
Language Guide:
$ npm run pulp:psci
> project3@1.0.0 pulp:psci /Users/bouzuya/project3
> pulp psci
Compiling Euler
PSCi, version 0.10.2
Type :? for help
> import Euler
> answer
233168
> :t answer
Int
> :q
See ya!
src/Main.purs
Euler
モジュールの実行のために src/Main.purs
を編集している。
src/Main.purs
:
module Main(main) where
import Prelude (Unit, (<>), show)
import Euler (answer)
import Control.Monad.Eff (Eff)
import Control.Monad.Eff.Console (CONSOLE, log)
main :: forall e. Eff (console :: CONSOLE | e) Unit
main = do
log ("The answer is " <> show answer)
これもまた、さきの例と似たような、ぼくなりの改変を入れた。 do
とかなくても通る気はするけど、そこは維持した。
$ npm run pulp:run
> project3@1.0.0 pulp:run /Users/bouzuya/project3
> pulp run
* Building project in/Users/bouzuya/project3
* Build successful.
The answer is 233168
よしよし。これで Getting Started はおしまい。
まとめ
2 で残していた psci
のコマンドをためしたのと Getting Started with PureScript を片付けた。
もっと基本的な言語仕様やパッケージなどを知らないと書けなさそうだ。
参考
- PureScript
- Getting Started with PureScript
- Language Guide
- Language Guide - Importing Modules
- Language Guide - Module Exports
次回以降の TODO
-
psc-package
を試す - PureScript Language Guide を読む
- PureScript by Example を読む
- 24 Days of PureScript, 2016 を読む
- 24 Days of PureScript, 2014 を読む
- 某氏の記事を紹介する