LoginSignup
2
3

More than 5 years have passed since last update.

PureScript の Getting Started を読む & 続 `psci` を試す

Last updated at Posted at 2016-12-04

この記事は (bouzuya) PureScript Advent Calendar 2016 の 4 日目。 (bouzuya) PureScript Advent Calendar 2016 は bouzuya の PureScript 学習の記録だ。

概要

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-listsData.List などのモジュールを提供するようだ。

pulp psciimport やコマンドをためす

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!

説明なんて冗長な感じもするけど……

  1. range で 0 以上 999 以下の整数の List をつくり、変数 ns を束縛する
  2. ns の各要素に対して、 mod で 3 の剰余をとって 0 、または 5 の剰余をとって 0 のみを filter で選択する
  3. sum でそれらの要素を合計する

という感じ。

JavaScript と文法事項を比較すると (差分が大きすぎる気もするけど) …… 、ここでは関数の呼び出しに () は要らないとか \x -> xx => 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 を片付けた。

もっと基本的な言語仕様やパッケージなどを知らないと書けなさそうだ。

参考

次回以降の TODO

2
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
3