この記事は (bouzuya) PureScript Advent Calendar 2016 の 7 日目です。 (bouzuya) PureScript Advent Calendar 2016 は bouzuya の PureScript 学習の記録です。
- ← 6 日目『 PureScript by Example 2 章を読む - Qiita 』
- → 8 日目『 PureScript by Example 3 章の後半を読む - Qiita 』
概要
昨日に続き PureScript by Example と PureScript Language Guide を見ながら進めていきます。今日は PureScript by Example の 3 章 の前半を読みます。
※注意事項: 英語と日本語訳では大きな差異があります。0.10.x
に対応している英語の側で進めます。
- PureScript by Example 2016-12-05 時点で 0.10.x 向け
- 実例による PureScript 2016-12-05 時点で 0.7 向け
- PureScript Language Guide 対象バージョン不明
PureScript by Example 3.1
この章では、関数とレコードという PureScript の構成要素を、アドレス帳アプリケーションという例を通じて学べるようです。
PureScript by Example 3.2
import Control.Plus (empty)
import Data.List (List(..), filter, head)
import Data.Maybe (Maybe)
Control.Plus
モジュールは purescript-control
パッケージに含まれているようですね。上記のコードはこの依存関係を解決できないので、ビルドできないですね……。 https://pursuit.purescript.org/packages/purescript-control/2.0.0/docs/Control.Plus
Data.List
モジュールは purescript-lists
パッケージに含まれているようですね。こちらはきちんと bower install
されています。 https://pursuit.purescript.org/packages/purescript-lists/3.2.1/docs/Data.List
Data.Maybe
モジュールは purescript-maybe
パッケージに含まれているようですね。こちらは purescript-lists
パッケージからの間接的な依存でなんとかビルドできるようですが、bower install
したほうが良い気がします。 https://pursuit.purescript.org/packages/purescript-maybe/2.0.1/docs/Data.Maybe
あとで Pull Request を投げてみましょうかね……。→ paf31/purescript-book は Pull Request 禁止のようです。 Issue で。
PureScript by Example 3.3
psci
の :type
で、基本的な型に触れています。 Language Guide の Types にあります。
Primitive Types が Number
/ String
/ Boolean
ですね。これはスルー。
そして Int
/ Array
/ Records
と。
Int
は Number
とは違い、整数に限定していますね。Array
は要素の型が一致してないとダメです。 Record
は JavaScript の object
ですね。
> chapter3@1.0.0 pulp:psci /Users/bouzuya/.ghq/github.com/paf31/purescript-book/exercises/chapter3
> pulp psci
PSCi, version 0.10.2
Type :? for help
> :type 1
Int
> :type 1.0
Number
> :type [1, 2, 3]
Array Int
> :type [true, false]
Array Boolean
> :type [1, false]
Error found:
in module $PSCI
at line 1, column 1 - line 1, column 11
Could not match type
Int
with type
Boolean
while inferring the type of [ 1
, false
]
in value declaration it
See https://github.com/purescript/purescript/wiki/Error-Code-TypesDoNotUnify for more information,
or to contribute content related to this error.
> let author = { name: "Phil", interests: ["Functional Programming", "JavaScript"] }
> :type author
{ name :: String
, interests :: Array String
}
> author.name
"Phil"
> author.interests
["Functional Programming","JavaScript"]
Language Guide の Tagged Unions と Newtypes は飛ばして、Functions ですね。Tagged Unions や Newtype もすぐ出てくるはず……。
> import Prelude (flip, const)
> :type flip
forall a b c. (a -> b -> c) -> b -> a -> c
> :type const
forall a b. a -> b -> a
psci
の :paste
を見せつつ、関数定義の例のようです。
> :paste
… let
… add :: Int -> Int -> Int
… add x y = x + y
…
Error found:
in module $PSCI
at line 3, column 13 - line 3, column 17
Unknown operator (+)
See https://github.com/purescript/purescript/wiki/Error-Code-UnknownName for more information,
or to contribute content related to this error.
> import Prelude ((+))
> :paste
… let
… add :: Int -> Int -> Int
… add x y = x + y
…
> add 10 20
30
> import Prelude ((*))
> let mul = \x y -> x * y
> mul 10 20
200
import Prelude
を限定していたので、 (+)
が読まれていなかったですね。関数のリテラルである \x -> x
の形式を見せる意図があったかもしれないので、ついでに mul
も書いてみました。 Language Guide の Functions も置いておきます。
PureScript by Example 3.4
forall
の話。Language Guide では Quantification かな。
↓の flip
についている forall
はこれが全称量化された型 (universally quantified type) ってことです、って説明されてますね。ぜんぜん分からないんですけど、任意の a
b
c
について↓の型で動くってことなんじゃないですかね。
> :type flip
forall a b c. (a -> b -> c) -> b -> a -> c
たとえば a
b
c
には Int
や String
などがはいるので、a
を Int
、 b
を String
、 c
を String
にすると、次のようになる、と。
(Int -> String -> String) -> String -> Int -> String
余談ですけど、型のこの表記は慣れないと困りますかね……。カリー化の話とかそのうち出てくるはずなので、スルーしますけど……。
flip
に関して言うと関数を受け取って第一引数と第二引数を入れ替えた関数にする関数です。
> :reset
> import Prelude ((<>), flip, show)
> flip (\n s -> show n <> s) "Ten" 10
"10Ten"
> :type show
forall a. (Show a) => a -> String
> :type (<>)
forall a. (Semigroup a) => a -> a -> a
ふむ。
show
は Show
インスタンスを受け取って String
を返す関数ですね。要するに .toString()
的なあれです。
https://pursuit.purescript.org/packages/purescript-prelude/2.1.0/docs/Data.Show#v:show
(<>)
は Semigroup
インスタンスをふたつ受け取ってくっつけて返します。Array.prototype.concat
的なあれです。 (<>)
は append
にたいしての operator alias です。これもそのうち出てくるはず……。
https://pursuit.purescript.org/packages/purescript-prelude/2.1.0/docs/Data.Semigroup#v:(%3C%3E)
これは書かれていますが、引数を逆にして flip (\n s -> show n <> s) 10 "Ten"
にすると動きません。show 10
の結果である "10"
と "Ten"
で "10" <> "Ten"
するから動くのであって、show "Ten"
の結果である "\"Ten\""
と 10
を <>
することはできません。型が違いますからね。
PureScript by Example 3.5
インデントの注意。雰囲気でインデントしてますけど、大丈夫ですね……。基本は同じブロックなら同じインデント、改行できそうなところで見た目のために改行したいなら、ひとつ深くインデントしておけば大丈夫。ブロックが終わればインデントを浅くする感じですかね。文字で読んでもなんとなくピンとこないですし、ルールとして書くと難しい感じはしますけど、素朴にインデントすると動くような……。うーん。
一応 Language Guide の Whitespace Rules を貼っておきます。
まとめ
まだ 3 章の前半ですけど、疲れてきたので、今日はこのへんでおしまいです。
参考
- PureScript by Example
- PureScript by Example - 3. Functions and Records
- paf31/purescript-book
- Language Guide
- Language Guide - Types
- Language Guide - Functions
- Language Guide - Quantification
- Language Guide - Whitespace Rules
- Pursuit
- https://pursuit.purescript.org/packages/purescript-control/2.0.0/docs/Control.Plus
- https://pursuit.purescript.org/packages/purescript-lists/3.2.1/docs/Data.List
- https://pursuit.purescript.org/packages/purescript-maybe/2.0.1/docs/Data.Maybe
- https://pursuit.purescript.org/packages/purescript-prelude/2.1.0/docs/Data.Show#v:show
- https://pursuit.purescript.org/packages/purescript-prelude/2.1.0/docs/Data.Semigroup#v:(%3C%3E)
次回以降の TODO
- PureScript by Example & PureScript Language Guide を読み進める
- Tagged Unions / Newtype
- カリー化
- Infix Operator / operator alias
psc-package
- PureScript IDE の導入
- 24 Days of PureScript, 2016
- 24 Days of PureScript, 2014
- 某氏の記事の紹介
- github.com/purescript のコードを読む
- github.com/purescript-node のコードを読む
- github.com/purescript-contrib のコードを読む