LoginSignup
0
2

More than 5 years have passed since last update.

PureScript by Example 4 章の前半を読む

Last updated at Posted at 2016-12-10

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

概要

PureScript by ExamplePureScript Language Guide を見ながら進めていく。今日は PureScript by Example の 4 章 の前半を読む。

※注意事項: 英語と日本語訳では大きな差異がある。0.10.x に対応している英語の側で進める。

PureScript 4.1

4 章は再帰関数を扱うようだ。 map fold filter concatMap は少なくとも登場するらしい。

例としては仮想のファイルシステムを扱う。ツリー構造を再帰かな……。

PureScript 4.2

今回のプロジェクトでは次のものをインストールするらしい。また Data.Path という使うだけのモジュールが必要らしい。資料を置いてあるリポジトリを参照すると良い。なぜ、いままでも使ってきた purescript-console をいまさらと思う。

  • purescript-maybe
  • purescript-arrays
  • purescript-strings
  • purescript-foldable-traversable
  • purescript-console

Pursuit:

PureScript by Example 4.3

再帰は重要。可変な状態を減らすことを助ける。なるほど。

再帰は分割統治と関係がある。ふむ。

fact :: Int -> Int
fact 0 = 1
fact n = n * fact (n - 1)

fib :: Int -> Int
fib 0 = 1
fib 1 = 1
fib n = fib (n - 1) + fib (n - 2)

それぞれの場合ごとに考えてつくっていけるってことかな。

PureScript by Example 4.4

配列の再帰。 length の例。 nullArray が空かを判定して、そうでなければ taillength で……という感じ。ふむり。

module Main where

import Prelude

import Data.Array (null)
import Data.Array.Partial (tail)
import Partial.Unsafe (unsafePartial)

length :: forall a. Array a -> Int
length arr =
  if null arr
    then 0
    else 1 + length (unsafePartial tail arr)

Pursuit:

そういえば if ... then ... else は初出なのかな。

unsafePartial は説明がないので、またそのうち出てくるはず。あと直接の依存関係にないのだけど、たぶん、purescript-arrays からの間接的な依存関係に入っているはず……。

PureScript by Example 4.5

map

> import Prelude (map)
> map (\n -> n + 1) [1, 2, 3, 4, 5]
[2,3,4,5,6]

> :type map
forall a b f. (Functor f) => (a -> b) -> f a -> f b

JavaScript の Array.prototype.map と動きは似ているけど、こちらは Prelude に入っているし、Array 以外でも (Functor なら) 使える。その説明は出ていないけど、そのうち出てくるはず。過去に AddressBook のところで Maybe が出てきたときに、使っていた気もする。

あと <$>map の operator alias (これも書いたはず) 。

Pursuit:

PureScript by Example 4.6

Infix Operator 。あれ、前もやったような……。中置演算子や中置関数適用 (infix function application) か。

> (\n -> n + 1) `map` [1, 2, 3, 4, 5]
[2, 3, 4, 5, 6]

> (\n -> n + 1) <$> [1, 2, 3, 4, 5]
[2, 3, 4, 5, 6]

> :type map
forall a b f. (Functor f) => (a -> b) -> f a -> f b

言ってるそばから <$>:type map が出てきた。

演算子を関数的に使う方法も前回書いたような気がする。

> import Prelude (map, show, (<$>))
> show <$> [1, 2, 3, 4, 5]
["1","2","3","4","5"]

> (<$>) show [1, 2, 3, 4, 5]
["1","2","3","4","5"]

range の operator alias である (..) を使ってみるらしい。

> import Data.Array ((..))
> 1 .. 5
[1,2,3,4,5]

> import Prelude (show, (<$>))
> show <$> (1 .. 5)
["1","2","3","4","5"]

Pursuit:

(..) の定義は次のようにするらしい。

infix 8 range as ..

ソースコードを見てみた。確かに。 https://github.com/purescript/purescript-arrays/blob/v3.1.0/src/Data/Array.purs#L161

PureScript by Example 4.7

filter 。 JavaScript の Array.prototype.filter はおなじみのはずなので、特に説明は不要かな。

> import Prelude (mod, (==))
> import Data.Array (filter, (..))
> filter (\n -> n `mod` 2 == 0) (1 .. 10)
[2,4,6,8,10]

> :t filter
forall a. (a -> Boolean) -> Array a -> Array a

Pursuit:

PureScript by Example 4.8

concat 。 JavaScript の Array.prototype.concat とは違い、flatten っぽい動き。

> import Data.Array (concat)
> :t concat
forall a. Array (Array a) -> Array a

> concat [[1, 2, 3], [4, 5], [6]]
[1,2,3,4,5,6]

Pursuit:

concatMap

> import Prelude ((*))
> import Data.Array (concatMap, (..))

> :t concatMap
forall a b. (a -> Array b) -> Array a -> Array b

> concatMap (\n -> [n, n * n]) (1 .. 5)
[1,1,2,4,3,9,4,16,5,25]

map して concat する感じ。語順のイメージは↓の concat $ map ... からだと思う。

> import Prelude (map, ($))
> concat (map (\n -> [n, n * n]) (1 .. 5))
[1,1,2,4,3,9,4,16,5,25]

> concat $ map (\n -> [n, n * n]) (1 .. 5)
[1,1,2,4,3,9,4,16,5,25]

Pursuit:

PureScript by Example 4.9

配列内包 (array comprehensions) 。因数を見つける関数を書くようだ。

まずは組み合わせを列挙するらしい。

> let pairs n = concatMap (\i -> 1 .. n) (1 .. n)
> pairs 3
[1,2,3,1,2,3,1,2,3]

> let pairs' n = concatMap (\i -> map (\j -> [i, j]) (1 .. n)) (1 .. n)
> pairs' 3
[[1,1],[1,2],[1,3],[2,1],[2,2],[2,3],[3,1],[3,2],[3,3]]

> let pairs'' n = concatMap (\i -> map (\j -> [i, j]) (i .. n)) (1 .. n)
> pairs' 3
[[1,1],[1,2],[1,3],[2,2],[2,3],[3,3]]
> import Prelude (map, (==))
> import Data.Array (concatMap, filter, (..))
> import Data.Foldable (product)
> let pairs'' n = concatMap (\i -> map (\j -> [i, j]) (i .. n)) (1 .. n)
> let factors n = filter (\pair -> product pair == n) (pairs'' n)
> factors 10
[[1,10],[2,5]]

product はソースによると foldl (*) oneoneSemiring のもの。

Pursuit:

まとめ

再帰関数。個人的には特にはまることなく、とんとんと進んだ。次は後半。

参考

0
2
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
0
2