SlideShare ist ein Scribd-Unternehmen logo
1 von 175
Downloaden Sie, um offline zu lesen
───When You Will Try Haskell
これから Haskell を書くにあたって
目次
3頁 … はじめに
9頁 … GHC 7.8 からの変更点
69頁 … Haskell が遅いと言われるワケとか
106頁 … 知らないと損する言語拡張たち
150頁 … FFI の話
161頁 … おまけ
はじめに
Who Am I?
twitter: func(@func_hs)
Haskell使いだったり、Clojure使いだったり。
現在求職中
最近E本ゲットしたからErlangも勉強する(その内)
はじめに
本発表の目的
Haskell には意外と落とし穴がある。
はじめに
本発表の目的
Haskell には意外と落とし穴がある。
✔ 計算量(オーダ)
はじめに
本発表の目的
Haskell には意外と落とし穴がある。
✔ 計算量(オーダ)
✔ メモリ使用量
はじめに
本発表の目的
Haskell には意外と落とし穴がある。
✔ 計算量(オーダ)
✔ メモリ使用量
✔ 言語仕様や処理系の実装のあれこれ
はじめに
本発表の目的
Haskell には意外と落とし穴がある。
✔ 計算量(オーダ)
✔ メモリ使用量
✔ 言語仕様や処理系の実装のあれこれ
これらへの注意の仕方と対処法を知る
GHC 7.8 からの変更点
10頁 … Monad Proposal
22頁 … Foldable
43頁 … Traversable
57頁 … Prelude の関数の変化
63頁 … 変更後の標準の型クラス全体図
67頁 … OpenGL から見る実装例
Monad Proposal
正確には Functor-Applicative-Monad Proposal
Monad のリファクタリングの提案
Monad は正式に Applicative の子型クラスに
話題自体は2014年よりも前から始まっていた。
最初期の Haskell では繋がっていたらしい。しかし…
親型クラスのメソッドをデフォルトで実装する機能がなかった。
Monad Proposal
instance 宣言のおさらい
記法
* instance C1 T1 where ...
* instance C1 a => T1 a where ...
* instance C1 a => Cn (T1 a) where ...
型クラスの実装をデータ型に対して与える
Monad Proposal
型変数のないデータ型への実装
instance C1 T1 where
f x = ...
型クラスの型変数は書かない
Monad Proposal
型変数のあるデータ型への実装
instance C1 a => T1 a where
f x = ...
instance (C1 a, C2 a, ...) => T1 a where
f x = ...
インスタンスを与える型変数を明示する
Monad Proposal
特定のインスタンスを持つデータ型への実装
instance C1 a => Cn (T1 a) where
f x = ...
instance (C1 a, C2 a,...) => Cn (T1 a) where
f x = ...
特定する型クラスも明示する
Monad Proposal
自動で実装できる型クラス
➜ deriving 句で導出できる型クラス
Eq, Ord, Enum, Bounded, Read, Show
コンストラクタの並び等から自明に導ける。
(もちろん自前で書いてもよい)
Monad Proposal
自動で実装できる型クラス
✔ 自明で導くことができる
✔ その型自身が直接依存する型クラス
に限る
Monad Proposal
Monad と Applicative の実装は?
❌自明では導くことができない
これら 2 つはコンテナの中身をどう扱うかの話
❌Applicative は Monad の親クラス
Monad のインスタンスを持つ型が直接依存しているわけではない。
Monad Proposal
公式の対応
return = pure
Monad の return の実装を Applicative の pure にリファクタリング
<*> = ap
コンテナから値を取り出し関数を適用するという点で同義
Monad Proposal
公式の対応
* pure :: a -> f a
* return :: a -> m a
* <*> :: f (a -> b) -> f a -> f b
* ap :: m (a -> b) -> m a -> m b
コンテキストが変わるだけ
Monad Proposal
公式の対応
Functor と Applicative の実装
➜ サードパーティが各自実装する形に
利便性より理論を優先?
Monad Proposal
Monad Proposal まとめ
✔ 2014年(GHC 7.8)以前に実装したモナドは
✔ リファクタリングしなきゃ(使命感)
Foldable
実装のイメージ
x1 x2 x3 x4 x5 …………………………… xN
f
?
コンテナの要素を一つに畳む
Foldable
期待される性質
✔ foldr f z t =
appEndo (foldMap (Endo . f) t) z
✔ foldl f z t =
appEndo (getDual (Dual . Endo . flip f) t)) z
✔ fold =
foldMap id
Foldable
期待される性質
Endo / appEndo
Dual / getDual
どちらも Data.Monoid モジュールにある
データ型
Foldable
期待される性質
newtype Endo a = Endo {appEndo :: a -> a}
モノイドのコンテキストで関数を合成する
Foldable
期待される性質
newtype Endo a = Endo {appEndo :: a -> a}
➜ instance Monoid (Endo a) where
mempty = Endo id
Endo f `mappend` Endo g = Endo (f . g)
Foldable
期待される性質
newtype Dual a = Dual {getDual :: a}
値を合成させるためのコンテナ
Foldable
期待される性質
newtype Dual a = Dual {getDual :: a}
➜ instance Monoid a => Monoid (Dual a)
where
mempty = Dual mempty
Dual x `mappend` Dual y =
Dual (x `mappned` y)
Foldable
Monoid に期待される性質
✔ mappend mempty x = x
✔ mappend x mempty = x
✔ mappend x (mappend y z) =
mappend (mappend x y) z
✔ mconcat = foldr mappend mempty
Foldable
Monoid に期待される性質
mappend mempty x = x
mappend x mempty = x
左単位元と右単位元の保証
Foldable
Monoid に期待される性質
mappend x (mappend y z) =
mappend (mappend x y) z
結合則の保証
Foldable
Monoid に期待される性質
mconcat = foldr mappend mempty
連結した結果が正しく閉じていることの保証
Foldable
Monoid に期待される性質
この内、必ず実装が必要なのは…
✔ mempty
✔ mappend
の 2 つ
Foldable
Monoid に期待される性質
mconcat にはデフォルト実装がある
➜ 特に必要なければ改めて実装しなくてよい
Foldable
話を戻して Foldable の話
foldr f z t =
appEndo (foldMap (Endo . f) t) z
foldl f z t =
appEndo (getDual (Dual . Endo . flip f) t)) z
要素の畳み方を定義する必要がある
Foldable
話を戻して Foldable の話
✔ foldMap
✔ foldr
最低限実装が必要なのはこの 2 つの内
少なくとも 1 つ
Foldable
話を戻して Foldable の話
✔ foldMap
✔ foldr
双方にデフォルト実装がある
➜ 片方が決まればもう片方も自動的に決まる
Foldable
話を戻して Foldable の話
foldMap :: Monoid m => (a -> m) -> t a -> m
foldMap f = foldr (mappend . f) mempty
Foldable のインスタンスを持つコンテナの要素を
Monoid に型変換させる
Foldable
話を戻して Foldable の話
foldr :: (a -> b -> b) -> b -> t a -> b
foldr f z t = appEndo (foldMap (Endo #. f) t) z
コンテナの中身をモノイドのコンテキストに
乗せながら畳んでいく
Foldable
話を戻して Foldable の話
foldr :: (a -> b -> b) -> b -> t a -> b
foldr f z t = appEndo (foldMap (Endo #. f) t) z
(´・_・`).oO((#.) ってなんだ?)
Foldable
話を戻して Foldable の話
(#.) :: (b -> c) -> (a -> b) -> (a -> c)
(#.) _f = coerce
coerce :: Coercible * a b => a -> b
coerce = let x = x in x
安全かつ強制的に型変換させるための関数
Foldable
Foldable まとめ
✔ 要素が Monoid のインスタンスであれば
どんな値も畳むことができる
✔ Endo は関数合成用のコンテナ
Dual は値合成用のコンテナ
✔ Monoid 用のデータ型は他にもあるよ!
Traversable
実装のイメージ
コンテナの要素に関数を適用し、入れ直す
x1 x2 x3 x4 x5 xN……………………………
f
y1 y2 y3 y4 y5 yN……………………………
Traversable
最低限実装が必要なメソッド
✔ traverse
✔ sequenceA
この 2 つの内いずれか 1 つ
双方にデフォルト実装がある。以下省略
Traversable
最低限実装が必要なメソッド
traverse
:: Applicative f => (a -> f b) -> t a -> f (t b)
traverse f = sequenceA . fmap f
コンテナの要素を走査しながら関数を適用
していく
Traversable
最低限実装が必要なメソッド
traverse
:: Applicative f => (a -> f b) -> t a -> f (t b)
traverse f = sequenceA . fmap f
コンテナが入れ替わることに注意
Traversable
最低限実装が必要なメソッド
sequenceA :: Applicative f => t (f a) -> f (t a)
sequenceA = traverse id
走査するだけ
(中の値自体には変更を加えない)
Traversable
最低限実装が必要なメソッド
sequenceA :: Applicative f => t (f a) -> f (t a)
sequenceA = traverse id
コンテナが入れ替わることに注意
(大事なことなのでry)
Traversable
最低限実装が必要なメソッド
コンテナを入れ替える理由
✔ 無駄なネストを除去し、
✔ 型の表現を簡潔にするため
(型注釈も込みで)
実装次第でより深いネストも走査できる
Traversable
最低限実装が必要なメソッド
コンテナを入れ替える理由
✔ 無駄なネストを除去し、
✔ 型の表現を簡潔にするため
(型注釈も込みで)
ただし注意が必要
Traversable
期待される性質
✔ t . traverse f =
traverse (t . f)
✔ traverse Identity =
Identity
✔ traverse (Compose . fmap g . f) =
Compose . fmap (traverse g) . traverse f
Traversable
期待される性質
✔ t . sequenceA =
sequenceA . fmap t
✔ sequenceA . fmap Identity =
Identity
✔ sequenceA . fmap Compose =
Compose . fmap sequenceA . sequenceA
Traversable
期待される性質
✔ t . traverse f = traverse (t . f)
✔ t . sequenceA = sequenceA . fmap t
関数合成の自然性の保証
(関数合成の効率化)
Traversable
期待される性質
✔ traverse Identity = Identity
✔ sequenceA . fmap Identity = Identity
同一性の保証
(id がちゃんとそのままの値を返すこと)
Traversable
期待される性質
✔ traverse (Compose . fmap g . f) =
Compose . fmap (traverse g) . traverse f
✔ sequenceA . fmap Compose =
Compose . fmap sequenceA . sequenceA
結合則の保証
Traversable
Traversable まとめ
✔ コンテナの要素を走査し、更新する
✔ その際にコンテナの構造を均して簡潔化する
✔ 中の要素は Applicative の実装が必要
(更新してコンテナに再適用させるため)
Prelude の関数の変化
意外とリファクタリングされていた
コンテナを畳むか走査するかで二分された
Prelude の関数の変化
意外とリファクタリングされていた
Foldableに所属
null, length, elem, notElem, maximum,
minimum, sum, product, and, or, any, all,
concat, concatMap, mapM_(forM_), sequence_
Prelude の関数の変化
意外とリファクタリングされていた
Traversableに所属
mapM(forM), sequence
Prelude の関数の変化
意外とリファクタリングされていた
mapM(forM)
コンテナ(変換結果)を返す
mapM_(forM_)
コンテナを返さない(命令の実行だけ)
Prelude の関数の変化
意外とリファクタリングされていた
sequence
結果を返すモナドなコンテナを評価する
sequence_
結果を返さないモナドなコンテナを評価する
Prelude の関数の変化
意外とリファクタリングされていた
sequence
評価して実行した結果をコンテナに詰め直す
sequence_
評価して実行するだけ(Unit型 `()` を返す)
変更後の標準の型クラス全体図
正式に養子縁組されました。
実線矢印が直接の継承関係
変更後の標準の型クラス全体図
正式に養子縁組されました。
点線矢印が挙動が類似している型クラス
変更後の標準の型クラス全体図
正式に養子縁組されました。
太線矢印(ArrowApply)は中の要素が Monad
変更後の標準の型クラス全体図
正式に養子縁組されました。
引用: Typeclassopedia
OpenGL から見る実装例
Foldable と Traversable はどう実装されているか
instance Foldable TexCoord4
foldr f a (TexCoord4 x y z w) =
x `f` (y `f` (z `f` (w `f` a)))
foldl f a (TexCoord4 x y z w) =
((((a `f` x) `f` y) `f` z) `f` w)
テクスチャ座標の畳込み等(一部抜粋)
OpenGL から見る実装例
Foldable と Traversable はどう実装されているか
instance Traversable TexCoord4 where
traverse f (TexCoord4 x y z w) =
pure TexCoord4 <*> f x <*> f y <*> f z
<*> f w
座標変換等(一部抜粋)
Haskell が遅いと言われるワケとか
70頁 … 評価しないものは溜まる
79頁 … データコンストラクタの中身
81頁 … 文字列の計算量とメモリ使用量
85頁 … タプル
88頁 … 自作データ型の高速化
97頁 … 型クラスの仕組み
102頁 … 競技プログラミングでの Haskell
評価しないものは溜まる
評価予定の値もスタックに
関数呼び出し中の未評価な値もスタックに乗る
➜ 評価されるまでは
評価しないものは溜まる
評価予定の値もスタックに
よくある階乗の計算
fact 0 = 1
fact n = n * fact (n - 1)
この n は何の問題もないように見えるが…
評価しないものは溜まる
評価予定の値もスタックに
よくある階乗の計算
fact 0 = 1
fact n = n * fact n
実は未評価なまま次の計算に渡されている
(評価されるのはパターンマッチの瞬間である)
評価しないものは溜まる
評価予定の値もスタックに
よくある階乗の計算
fact 0 = 1
fact n = n * fact n
引数部に名前だけの場合、それはパターンマッチ
されないことに注意。
評価しないものは溜まる
評価予定の値もスタックに
呼び出し回数が少ない内は無事に動く
➜ スタックもそれほど溜まらない
評価しないものは溜まる
評価予定の値もスタックに
しかし呼び出す回数が増えるにつれて、スタックは
どんどん溜まっていき、いずれは溢れてしまう
➜ 渡された値も未評価のまま…
この現象をスペースリークという
評価しないものは溜まる
評価予定の値もスタックに
対処法
✔ 他の関数に渡す前に強制的に評価させる
➜ seq 関数(この節で説明)
➜ BangPatterns(148頁)
評価しないものは溜まる
その場で評価させる方法
seq 関数
渡された値をその場で評価する(評価するだけ)
seq :: a -> b -> b
seq = let x = x in x
評価しないものは溜まる
その場で評価させる方法
階乗の例に適用してみる
fact 0 = 1
fact n = n `seq` n * fact (n - 1)
これにより、 n は seq 関数に渡され、その場で評
価されるようになった
データコンストラクタの中身
値がそのまま入るわけではない
Maybe Intの場合
Nothing Just
I# Int#
or P
P: ポインタ
データコンストラクタの中身
値がそのまま入るわけではない
Maybe Intの場合
Nothing Just
I# Int#
or P
P: ポインタ
実際の Int 型の値
文字列の計算量とメモリ使用量
計算量多そう…
: P
"Hello"(UTF-8)
P P
C# Char#
'H'
P P
C# Char#
'e'
P
C# Char#
'l'
P P P
C# Char#
'l'
P : : : :
文字列の計算量とメモリ使用量
計算量多い(確信)
"Hello"(UTF-8)
: P P P
C# Char#
'H'
P P
C# Char#
'e'
P
C# Char#
'l'
P P P
C# Char#
'l'
P : : : :
⑲
⑱
⑰⑯
⑮⑩⑤
⑭
⑬
⑫⑪
⑨
⑧
⑦⑥
③
②① ㉒㉑ ㉓
④
⑳
1 文字だけでも 4 回以上の計算が…
文字列の計算量とメモリ使用量
メモリ食いすぎィ!
構築子: 1 word
型引数: 1 word / arg
文字列 1 文字分 = 5 words
構築子(:) + ポインタ * 2 + Char のサイズ
1 word 2 words 2 words
C# + Char#
※32bit: 20 bytes, 64bit: 40 bytes
文字列の計算量とメモリ使用量
文字列効率化の試み
ライブラリレベル
➜ bytestring
➜ text
処理系レベル
➜ OverloadedStrings(98頁)
タプル
タプルも例外ではない
(,)
(Int, Int)
P P
I# Int# I# Int#
(Int, Int, Int)
(,) P P
I# Int#
P
I# Int#
I# Int#
タプル
タプルも例外ではない
(Maybe Int, Maybe Int)
(,) P P
Nothing or Just P
Nothing or Just P
I# Int#
I# Int#
タプル
タプルの高速化
➜ UnboxedTuples(108頁)
自作データ型の高速化
正格性フラグ
data T = T !Int
フラグ(!)の付いた型引数は正格評価される
✔ 受け取ったその場で評価
✔ 遅延評価ならではのデメリットは解消される
自作データ型の高速化
正格性フラグ
data T = T !Int
フラグ(!)の付いた型引数は正格評価される
❌ その値はデータ生成時に直ちに
渡されなければならない
❌ その型を部分適用できなくなる
自作データ型の高速化
正格性フラグ
関数に付与する場合
➜ BangPatterns(148頁)
自作データ型の高速化
標準にあるハッシュ付きの型は Unpack 可能
Int, Integer, Float, Double, Char, Word[N],
Int[N]
これらはライブラリではただの Unpack 可能な型
➜ プリミティブな値は処理系が保持
自作データ型の高速化
標準にあるハッシュ付きの型は Unpack 可能
data T a = T {-# Unpack #-} !Int
T Int#
プリミティブな値がそのまま型引数に収まる
✔ 計算量とメモリ消費量が減る
✔ 生の値なので遅延評価不可
(正格性フラグ必須)
ただのバイナリ
自作データ型の高速化
標準にあるハッシュ付きの型は Unpack 可能
data T a = T {-# Unpack #-} !Int
T Int#
プリミティブな値がそのまま型引数に収まる
❌ 構築子が 1 つだけの型に限る
❌ 通常の型と同じようには使えない
ただのバイナリ
自作データ型の高速化
標準にあるハッシュ付きの型は Unpack 可能
data T a = T {-# Unpack #-} !Int
T Int#
プリミティブな値がそのまま型引数に収まる
❌ 複数あると処理系が判断できない
❌ 通常の型はポインタであると期待される
ただのバイナリ
自作データ型の高速化
標準にあるハッシュ付きの型は Unpack 可能
data T a = T {-# Unpack #-} !Int
T Int#
プリミティブな値がそのまま型引数に収まる
❌ 複数あると処理系が判断できない
❌ 許してしまうと GC の対象になり、
厄介なバグを生みやすくなる
ただのバイナリ
自作データ型の高速化
標準にあるハッシュ付きの型は Unpack 可能
data T a = T {-# Unpack #-} !Int
T Int#
プリミティブな値がそのまま型引数に収まる
❌ 複数あると処理系が判断できない
⚠ 不本意な再ボックス化を防ぐために
最適化オプションを付けるべき
ただのバイナリ
型クラスの仕組み
その正体は辞書
型クラスへの依存(もとい制約)情報は
辞書型のデータ構造によって管理される
型クラスの仕組み
その正体は辞書
:: C a => a
1. C a という制約が導入されて、
2. C a の情報を持つ辞書に型 a の値が適用される
型クラスの仕組み
その正体は辞書
:: C a => a
⚠ 型変数は、注釈中のいずれかのデータ型に
必ず到達できなければならない
型クラスの仕組み
その正体は辞書
:: C a => Hoge ❌
➜ C a だけではインスタンスを特定できない
型クラスの仕組み
その正体は辞書
⚠ インタプリタ(一般に GHCi)では遅い
➜ 制約の辞書も逐次生成される
➜ コンパイル、しよう(提案)
競技プログラミングでの Haskell
速度にシビアな問題では死ぬ
✔ 主に TLE で。
➜ 標準の文字列や List 等では間に合わない
問題がある
➜ それを埋め合わせるライブラリが使えない
➜ そもそも型の構造的に辛い…
競技プログラミングでの Haskell
速度にシビアな問題では死ぬ
対策
✔ 言語拡張を導入(詳細は後述)
➜ UnboxedTuples
➜ OverloadedStrings(※)
➜ OverloadedLists(※)
➜ BangPatterns
競技プログラミングでの Haskell
速度にシビアな問題では死ぬ
※のある拡張は競プロでは使用不可
bytestring も text も vector も競プロの
サイト側では用意されていない…
競技プログラミングでの Haskell
Haskell が使える競プロサービス
AtCoder
✔ GHC 7.8 以降
Codeforces
✔ GHC 7.8 以降
他
❌ (GHC がインストールされて)ないです…
知らないと損する言語拡張たち
107頁 … リテラルを置き換える
117頁 … 計算量を削減する
120頁 … データ型の表現力を向上する
122頁 … 型クラスの表現力を向上する
148頁 … 評価戦力を切り替える
リテラルを置き換える
Overloaded Strings
✔ 文字列(文字のリスト) を IsString の
インスタンスを持つ別の何かに昇格
例) ByteString, Text
IsString さえ実装されていればどんな型でもよい
リテラルを置き換える
Overloaded Strings
ByteString の例
instance IsString ByteString where
fromString = packChars
文字列を packChars に丸投げする
リテラルを置き換える
Overloaded Strings
Text の例
instance IsString Text where
fromString = pack
文字列を pack に丸投げする
リテラルを置き換える
Overloaded Strings
Data.ByteString を import してると
"Hello" :: ByteString
Data.Text を import してると
"Hello" :: Text
リテラルを置き換える
Overloaded Lists
✔ 何らかの List を IsList のインスタンスを持つ
別の何かに昇格
例) vector
IsList さえ実装されていればどんな型でもよい
リテラルを置き換える
Overloaded Lists
Vector の例
instance Ext.IsList (Vector a) where
type Item (Vector a) = a
fromList = fromList
fromListN = fromListN
toList = toList
リテラルを置き換える
Overloaded Lists
Vector の例
type Item (Vector a) = a
Item (Vector a) という型の組み合わせを型 a
として扱わせる言語拡張(ここでは触れない)
See: 7.7 Type families - The User's Guide
リテラルを置き換える
Overloaded Lists
Vector の例
fromList = fromList
List を Vector.fromList に丸投げ
リテラルを置き換える
Overloaded Lists
Vector の例
fromList = fromListN
List を Vector.fromListN に丸投げ
(List の最初の N 要素だけを Vector に入れる)
リテラルを置き換える
Overloaded Lists
Vector の例
toList = toList
Vector を List に変換する
計算量を削減する
Unboxed Tuples
Tuple からタグ(ポインタ部分)を取り除く
➜ ただの限定的な連続領域になる
➜ ポインタを挟まず、要素がスタックや
レジスタに直接置かれる
➜ Unpack されていない要素は通常通り
遅延評価される
計算量を削減する
Unboxed Tuples
Tuple からタグ(ポインタ部分)を取り除く
❌ (多層的な)型や関数の引数には渡せない
➜ 型ではない。
➜ ポインタを持っていない
➜ 引数ではない部分でなら問題ない
(返り値にする時や case 式など)
計算量を削減する
Unboxed Tuples
(Int, Int)
(,) P P
I# Int# I# Int#
(# Int, Int #)
I# Int# I# Int#
連続した領域として
扱われる
データ型の表現力を向上する
GADTs
データコンストラクタにも関数と同じ型注釈を
使えるようにする
data T a = T1 | T2 a (T a)
➜ data T a where
T1 :: T a
T2 :: a -> T a -> T a
データ型の表現力を向上する
GADTs
データコンストラクタにも関数と同じ型注釈を使え
るようにする
✔ 構造がネストするコンストラクタも楽に
定義できるようになる
やったぜ。
型クラスの表現力を向上する
Multi Param Type Classes
型クラスに複数の型変数を許可する
➜ メソッドが複数の異なるインスタンスを
受け取れるようになる
class C a b where
f :: a -> b -> b
型クラスの表現力を向上する
Functional Dependencies
型変数の関係性を明示する
➜ ある型が決まれば別の型も一意に決まる と
いう(依存)関係
class C a b | a -> b where
型クラスの表現力を向上する
Flexible Instances
instance 宣言のルールを緩和する
➜ より柔軟にインスタンスを実装できる
型クラスの表現力を向上する
Flexible Instances
通常時のルール
✔ 1 つの型クラスにつき型変数は 1 つまで
✔ 型変数の重複は許されない
✔ 制約は型変数にのみ与えられる
✔ 実装は必ずしなければならない
型クラスの表現力を向上する
Flexible Instances
拡張導入後のルール
➜ 多変数型クラスの実装を与えてもよい
➜ 型変数は重複していてもよい
➜ 代数的データ型を混ぜてもよい
➜ 宣言のみであってもよい
型クラスの表現力を向上する
Flexible Instances
拡張導入後のルール
✔ instance C a b where ...
✔ instance C a a where ...
✔ instance C a Int where ...
✔ instance C a b (=> ...)
型クラスの表現力を向上する
Flexible Instances
拡張導入後のルール
✔ 型シノニムも宣言に書ける
data T a = T1 | T2 a (T a)
type TT = T Int
instance Eq TT where ...
型クラスの表現力を向上する
Flexible Instances
注意点
⚠ 柔軟化した分、処理系は実装を
特定しにくくなる
型クラスの表現力を向上する
Flexible Instances
例1
class C a b
instance C a Int
instance C Int b
a と b のどちらに Int があっても特定できてしまう
型クラスの表現力を向上する
Flexible Instances
例2
class C a b
instance C Int b
instance C Int [b]
多相型なので一番目の b にも List があり得る
型クラスの表現力を向上する
Flexible Contexts
制約の文法に FlexibleInstance と同じ緩和を適用
する
型クラスの表現力を向上する
Flexible Contexts
⚠ 型変数に言及しなくてよい注釈は存在しない
❌ f :: C a b => Int
❌ f :: C a b => a -> Int
型クラスの表現力を向上する
Flexible Contexts
✔ それ以外は Flexible Instances と同様に書ける
➜ f :: C a b => a -> b -> b
➜ f :: C a a => a -> a -> a
➜ f :: C a (T b) => a -> a -> T b
➜ f :: C a TT => a -> a -> TT
型クラスの表現力を向上する
Overlapping Instances
特定可能なインスタンスの定義が複数ある場合
に、特定先を 1 つに絞らせる
型クラスの表現力を向上する
Overlapping Instances
⚠ 最も特殊性の高い(※)インスタンスが
1 つ以上存在している必要がある。
(※具体的に型が決められていること)
型クラスの表現力を向上する
Overlapping Instances
次のような制約のある注釈を考える
:: C Int Int -> Int -> Int -> a
型クラスの表現力を向上する
Overlapping Instances
以下のインスタンスが定義されているとする
instance C a Int
instance C Int b
instance C Int Int
型クラスの表現力を向上する
Overlapping Instances
この内、最も特殊性が高いのは茶色の定義
instance C Int b
instance C a Int
instance C Int Int
型クラスの表現力を向上する
Overlapping Instances
よって、
:: C Int Int -> Int -> Int -> a
という制約に対して
instance C Int Int
の定義がマッチされる
型クラスの表現力を向上する
Overlapping Instances
⚠ 特殊性の高いインスタンスがひとつもないと
判断された場合はエラーになる
型クラスの表現力を向上する
Overlapping Instances
instance C Int b
instance C a Int
だけだと特定のしようがない…(エラー)
型クラスの表現力を向上する
Incoherent Instances
特殊性のあるインスタンスが 1 つも
見つからなかった場合に、最もパターンの近い
インスタンスを選ばせる
型クラスの表現力を向上する
Incoherent Instances
:: C Int Int -> Int -> Int -> a
という制約に最も適合するインスタンスは
instance C Int Int
だが、これがない場合は
型クラスの表現力を向上する
Incoherent Instances
instance C Int b
instance C a Int
のいずれかを選択させる
型クラスの表現力を向上する
Incoherent Instances
⚠ どのインスタンスが選ばれるのかは、制約を
与えられた関数が呼び出されるまで
わからない
➜ インスタンスの選択を遅延させている
➜ 同じ制約のつもりでも違うインスタンスを
選択される可能性がある
型クラスの表現力を向上する
Incoherent Instances
✔ 複数適合しうるインスタンスをなるべく
書かないようにすることが大事
評価戦略を切り替える
Bang Patterns
関数の引数にも正格性フラグを付与できるように
する
f !x = x * 2
この関数の引数 x は正格評価される
評価戦略を切り替える
Bang Patterns
⚠ 当然ながら遅延評価ではないので、部分適用は
できない
FFIの話
151頁 … 呼び出せるプログラミング言語
154頁 … 呼び出し方
156頁 … Haskell での型の扱い
158頁 … ByteString から見る実装例
160頁 … hmatrix から見る実装例
呼び出せるプログラミング言語
対応状況
C
✔ 標準で使える
C++
▲ extern C 必須
❌ class や template は使用不可
(C と共通する部分のみ使用可)
呼び出せるプログラミング言語
対応状況
Java
✔ java-bridge があるが…
➜ 最近更新されてない…
➜ JNI と闘う覚悟はあるか?
(俺はない(´・_・`))
呼び出せるプログラミング言語
対応状況
.NET
✔ hs-dotnet があるが…
➜ 最近更新されてない…
➜ 恐らく開発自体が止まっている…
呼び出し方
構文(import)
foreign import callconv impent var :: ftype
callconv :=
ccall | stdcall | cplusplus | jvm | dotnet
impent := [string]
(呼び出すヘッダの名前と関数の名前。スペース区切り。なくてもよい)
呼び出し方
構文(export)
foreign export callconv expent var :: ftype
callconv :=
ccall | stdcall | cplusplus | jvm | dotnet
expent := [string]
(呼び出すヘッダの名前と関数の名前。スペース区切り。なくてもよい)
Haskell での型の扱い
型対応表
Haskell → C C → Haskell
CInt HsInt
CFloat HsFloat
CDouble HsDouble
Bool HsBool
Haskell での型の扱い
型対応表
Haskell → C C → Haskell
Ptr a * p
(ポインタ)
FunPtr a int (*p)(int)
(関数ポインタ)
ByteString から見る実装例
C の型を操作するので unsafe
foreign import ccall unsafe "string.h memchr"
c_memchr :: Ptr Word8 -> CInt -> CSize
-> IO (Ptr Word8)
ByteString から見る実装例
C の型を操作するので unsafe
memchr :: Ptr Word8 -> Word8 -> CSize
-> IO (Ptr Word8)
memchr p w s =
c_memchr p (fromIntegral w) s
hmatrix から見る実装例
行列演算ライブラリ
foreign import ccall unsafe "sort_indexD"
c_sort_indexD
:: CV Double (CV CInt (IO CInt))
C と Haskell の間を往復するのでオーバーヘッドが
すごいらしい…
(まだ使ったことがないので詳しくはなんとも…)
おまけ
162頁 … あると便利な言語拡張たち
171頁 … CPP
あると便利な言語拡張たち
BinaryLiterals
二進数による数値表現を可能にする
0b1010 -> 10(10進数)
あると便利な言語拡張たち
LambdaCase
無名関数の要領で case 式を書ける
(case 式に渡すデータの名前を省略できる)
case
p1 -> e1
p2 -> e1
....
あると便利な言語拡張たち
MagicHash
リテラルや型コンストラクタに ハッシュ(#)を使う
ことを許可する
✔ ハッシュ(#)自体には特に意味はない
✔ 慣習的に内部にプリミティブな値を
持っている型に付与されている
あると便利な言語拡張たち
MagicHash
リテラルや型コンストラクタにハッシュ(#)を使う
ことを許可する
'x'# Char➜ #
"foo"# Addr➜ #
3# Int➜ #
3## Word➜ #
あると便利な言語拡張たち
ParallelListComp
複数のリストを同時に内包表記できる
[(x, y) | x <- xs | y <- ys]
これは
zip xs ys
と同じことをしている
あると便利な言語拡張たち
ParallelListComp
お馴染みフィボナッチ数列
fibs =
0 : 1 : [a + b | a <- fibs | b <- tail fibs]
これは
fibs = 0 : 1 : zipWith (+) fibs (tail fibs)
と同じ
あると便利な言語拡張たち
PatternGuards
引数のパターンマッチの柔軟性が増す
通常
f :: Int -> Bool
f x
| n <= x && x <= m = ...
| otherwise = ...
あると便利な言語拡張たち
PatternGuards
引数のパターンマッチの柔軟性が増す
複数の条件を同時に書ける
f :: Int -> Bool
f x
| n <= x && x <= m, x >= n * 100 = ...
| otherwise = ...
あると便利な言語拡張たち
PatternGuards
引数のパターンマッチの柔軟性が増す
これは(||)を適用してるのと同じ
f :: Int -> Bool
f x
| n <= x && x <= m || x >= n * 100 = ...
| otherwise = ...
CPP
実は C 由来のプリプロセッサを書ける
GHC の時のみそのコードが動くようにする
{-# LANGUAGE CPP #-}
#ifdef __GLASGOW_HASKELL__
-- Some Codes Here
#endif
CPP
実は C 由来のプリプロセッサを書ける
GHC の時のみそのコードが動くようにする
{-# LANGUAGE CPP #-}
#ifdef __GLASGOW_HASKELL__
-- Some Codes Here
#endif
CPP
実は C 由来のプリプロセッサを書ける
GHC の特定のバージョンでのみそのコードが動く
ようにする
{-# LANGUAGE CPP #-}
#if __GLASGOW_HASKELL__==780
-- Some Codes Here
#endif
おしまい
話したいことまだまだたくさん
❌ 時間足りない
❌ 話もどんどん複雑化
➜ またの機会に話そうと思う
(機会がなければその内 Qiita に投稿する)
おしまい
───See You Again!

Weitere ähnliche Inhalte

Was ist angesagt?

プログラミングコンテストでの動的計画法
プログラミングコンテストでの動的計画法プログラミングコンテストでの動的計画法
プログラミングコンテストでの動的計画法
Takuya Akiba
 
C++ Template Meta Programming の紹介@社内勉強会
C++ Template Meta Programming の紹介@社内勉強会C++ Template Meta Programming の紹介@社内勉強会
C++ Template Meta Programming の紹介@社内勉強会
Akihiko Matuura
 
Constexpr 中3女子テクニック
Constexpr 中3女子テクニックConstexpr 中3女子テクニック
Constexpr 中3女子テクニック
Genya Murakami
 
Pythonの理解を試みる 〜バイトコードインタプリタを作成する〜
Pythonの理解を試みる 〜バイトコードインタプリタを作成する〜Pythonの理解を試みる 〜バイトコードインタプリタを作成する〜
Pythonの理解を試みる 〜バイトコードインタプリタを作成する〜
Preferred Networks
 
オブジェクト指向できていますか?
オブジェクト指向できていますか?オブジェクト指向できていますか?
オブジェクト指向できていますか?
Moriharu Ohzu
 
プログラミングコンテストでのデータ構造
プログラミングコンテストでのデータ構造プログラミングコンテストでのデータ構造
プログラミングコンテストでのデータ構造
Takuya Akiba
 
Cache-Oblivious データ構造入門 @DSIRNLP#5
Cache-Oblivious データ構造入門 @DSIRNLP#5Cache-Oblivious データ構造入門 @DSIRNLP#5
Cache-Oblivious データ構造入門 @DSIRNLP#5
Takuya Akiba
 

Was ist angesagt? (20)

何となく勉強した気分になれるパーサ入門
何となく勉強した気分になれるパーサ入門何となく勉強した気分になれるパーサ入門
何となく勉強した気分になれるパーサ入門
 
C++コミュニティーの中心でC++をDISる
C++コミュニティーの中心でC++をDISるC++コミュニティーの中心でC++をDISる
C++コミュニティーの中心でC++をDISる
 
C#とILとネイティブと
C#とILとネイティブとC#とILとネイティブと
C#とILとネイティブと
 
すごい配列楽しく学ぼう
すごい配列楽しく学ぼうすごい配列楽しく学ぼう
すごい配列楽しく学ぼう
 
モナドをつくろう
モナドをつくろうモナドをつくろう
モナドをつくろう
 
プログラミングコンテストでの動的計画法
プログラミングコンテストでの動的計画法プログラミングコンテストでの動的計画法
プログラミングコンテストでの動的計画法
 
プログラムの処方箋~健康なコードと病んだコード
プログラムの処方箋~健康なコードと病んだコードプログラムの処方箋~健康なコードと病んだコード
プログラムの処方箋~健康なコードと病んだコード
 
C++ Template Meta Programming の紹介@社内勉強会
C++ Template Meta Programming の紹介@社内勉強会C++ Template Meta Programming の紹介@社内勉強会
C++ Template Meta Programming の紹介@社内勉強会
 
Marp Tutorial
Marp TutorialMarp Tutorial
Marp Tutorial
 
Constexpr 中3女子テクニック
Constexpr 中3女子テクニックConstexpr 中3女子テクニック
Constexpr 中3女子テクニック
 
Pythonの理解を試みる 〜バイトコードインタプリタを作成する〜
Pythonの理解を試みる 〜バイトコードインタプリタを作成する〜Pythonの理解を試みる 〜バイトコードインタプリタを作成する〜
Pythonの理解を試みる 〜バイトコードインタプリタを作成する〜
 
オブジェクト指向できていますか?
オブジェクト指向できていますか?オブジェクト指向できていますか?
オブジェクト指向できていますか?
 
「Python言語」はじめの一歩 / First step of Python
「Python言語」はじめの一歩 / First step of Python「Python言語」はじめの一歩 / First step of Python
「Python言語」はじめの一歩 / First step of Python
 
ソーシャルゲーム案件におけるDB分割のPHP実装
ソーシャルゲーム案件におけるDB分割のPHP実装ソーシャルゲーム案件におけるDB分割のPHP実装
ソーシャルゲーム案件におけるDB分割のPHP実装
 
Binary indexed tree
Binary indexed treeBinary indexed tree
Binary indexed tree
 
たのしい関数型
たのしい関数型たのしい関数型
たのしい関数型
 
F#入門 ~関数プログラミングとは何か~
F#入門 ~関数プログラミングとは何か~F#入門 ~関数プログラミングとは何か~
F#入門 ~関数プログラミングとは何か~
 
プログラミングコンテストでのデータ構造 2 ~平衡二分探索木編~
プログラミングコンテストでのデータ構造 2 ~平衡二分探索木編~プログラミングコンテストでのデータ構造 2 ~平衡二分探索木編~
プログラミングコンテストでのデータ構造 2 ~平衡二分探索木編~
 
プログラミングコンテストでのデータ構造
プログラミングコンテストでのデータ構造プログラミングコンテストでのデータ構造
プログラミングコンテストでのデータ構造
 
Cache-Oblivious データ構造入門 @DSIRNLP#5
Cache-Oblivious データ構造入門 @DSIRNLP#5Cache-Oblivious データ構造入門 @DSIRNLP#5
Cache-Oblivious データ構造入門 @DSIRNLP#5
 

Ähnlich wie これから Haskell を書くにあたって

Ekmett勉強会発表資料
Ekmett勉強会発表資料Ekmett勉強会発表資料
Ekmett勉強会発表資料
時響 逢坂
 
Lisp tutorial for Pythonista : Day 1
Lisp tutorial for Pythonista : Day 1Lisp tutorial for Pythonista : Day 1
Lisp tutorial for Pythonista : Day 1
Ransui Iso
 
ZFSのソースコードをチラ見してみる
ZFSのソースコードをチラ見してみるZFSのソースコードをチラ見してみる
ZFSのソースコードをチラ見してみる
Koichi Suzuki
 
Scalaプログラミング・マニアックス
Scalaプログラミング・マニアックスScalaプログラミング・マニアックス
Scalaプログラミング・マニアックス
Tomoharu ASAMI
 

Ähnlich wie これから Haskell を書くにあたって (20)

これから Haskell を書くにあたって
これから Haskell を書くにあたってこれから Haskell を書くにあたって
これから Haskell を書くにあたって
 
How wonderful to be (statically) typed 〜型が付くってスバラシイ〜
How wonderful to be (statically) typed 〜型が付くってスバラシイ〜How wonderful to be (statically) typed 〜型が付くってスバラシイ〜
How wonderful to be (statically) typed 〜型が付くってスバラシイ〜
 
モナドハンズオン前座
モナドハンズオン前座モナドハンズオン前座
モナドハンズオン前座
 
思ったほど怖くない! Haskell on JVM 超入門 #jjug_ccc #ccc_l8
思ったほど怖くない! Haskell on JVM 超入門 #jjug_ccc #ccc_l8思ったほど怖くない! Haskell on JVM 超入門 #jjug_ccc #ccc_l8
思ったほど怖くない! Haskell on JVM 超入門 #jjug_ccc #ccc_l8
 
Ekmett勉強会発表資料
Ekmett勉強会発表資料Ekmett勉強会発表資料
Ekmett勉強会発表資料
 
Introduction to NumPy & SciPy
Introduction to NumPy & SciPyIntroduction to NumPy & SciPy
Introduction to NumPy & SciPy
 
asm.js x emscripten: The foundation of the next level Web games
asm.js x emscripten: The foundation of the next level Web gamesasm.js x emscripten: The foundation of the next level Web games
asm.js x emscripten: The foundation of the next level Web games
 
Ekmett勉強会発表資料
Ekmett勉強会発表資料Ekmett勉強会発表資料
Ekmett勉強会発表資料
 
Haskell Lecture 2
Haskell Lecture 2Haskell Lecture 2
Haskell Lecture 2
 
Applicative functor
Applicative functorApplicative functor
Applicative functor
 
Freer Monads, More Extensible Effects
Freer Monads, More Extensible EffectsFreer Monads, More Extensible Effects
Freer Monads, More Extensible Effects
 
RのffでGLMしてみたけど...
RのffでGLMしてみたけど...RのffでGLMしてみたけど...
RのffでGLMしてみたけど...
 
LastaFluteでKotlinをはじめよう
LastaFluteでKotlinをはじめようLastaFluteでKotlinをはじめよう
LastaFluteでKotlinをはじめよう
 
Lisp tutorial for Pythonista : Day 1
Lisp tutorial for Pythonista : Day 1Lisp tutorial for Pythonista : Day 1
Lisp tutorial for Pythonista : Day 1
 
ZFSのソースコードをチラ見してみる
ZFSのソースコードをチラ見してみるZFSのソースコードをチラ見してみる
ZFSのソースコードをチラ見してみる
 
Scalaプログラミング・マニアックス
Scalaプログラミング・マニアックスScalaプログラミング・マニアックス
Scalaプログラミング・マニアックス
 
transformer解説~Chat-GPTの源流~
transformer解説~Chat-GPTの源流~transformer解説~Chat-GPTの源流~
transformer解説~Chat-GPTの源流~
 
関数型言語&形式的手法セミナー(3)
関数型言語&形式的手法セミナー(3)関数型言語&形式的手法セミナー(3)
関数型言語&形式的手法セミナー(3)
 
20180728 halide-study
20180728 halide-study20180728 halide-study
20180728 halide-study
 
JSX / Haxe / TypeScript
JSX / Haxe / TypeScriptJSX / Haxe / TypeScript
JSX / Haxe / TypeScript
 

Kürzlich hochgeladen

Kürzlich hochgeladen (11)

論文紹介: The Surprising Effectiveness of PPO in Cooperative Multi-Agent Games
論文紹介: The Surprising Effectiveness of PPO in Cooperative Multi-Agent Games論文紹介: The Surprising Effectiveness of PPO in Cooperative Multi-Agent Games
論文紹介: The Surprising Effectiveness of PPO in Cooperative Multi-Agent Games
 
論文紹介:Selective Structured State-Spaces for Long-Form Video Understanding
論文紹介:Selective Structured State-Spaces for Long-Form Video Understanding論文紹介:Selective Structured State-Spaces for Long-Form Video Understanding
論文紹介:Selective Structured State-Spaces for Long-Form Video Understanding
 
Amazon SES を勉強してみる その32024/04/26の勉強会で発表されたものです。
Amazon SES を勉強してみる その32024/04/26の勉強会で発表されたものです。Amazon SES を勉強してみる その32024/04/26の勉強会で発表されたものです。
Amazon SES を勉強してみる その32024/04/26の勉強会で発表されたものです。
 
Observabilityは従来型の監視と何が違うのか(キンドリルジャパン社内勉強会:2022年10月27日発表)
Observabilityは従来型の監視と何が違うのか(キンドリルジャパン社内勉強会:2022年10月27日発表)Observabilityは従来型の監視と何が違うのか(キンドリルジャパン社内勉強会:2022年10月27日発表)
Observabilityは従来型の監視と何が違うのか(キンドリルジャパン社内勉強会:2022年10月27日発表)
 
新人研修 後半 2024/04/26の勉強会で発表されたものです。
新人研修 後半        2024/04/26の勉強会で発表されたものです。新人研修 後半        2024/04/26の勉強会で発表されたものです。
新人研修 後半 2024/04/26の勉強会で発表されたものです。
 
LoRaWAN スマート距離検出デバイスDS20L日本語マニュアル
LoRaWAN スマート距離検出デバイスDS20L日本語マニュアルLoRaWAN スマート距離検出デバイスDS20L日本語マニュアル
LoRaWAN スマート距離検出デバイスDS20L日本語マニュアル
 
知識ゼロの営業マンでもできた!超速で初心者を脱する、悪魔的学習ステップ3選.pptx
知識ゼロの営業マンでもできた!超速で初心者を脱する、悪魔的学習ステップ3選.pptx知識ゼロの営業マンでもできた!超速で初心者を脱する、悪魔的学習ステップ3選.pptx
知識ゼロの営業マンでもできた!超速で初心者を脱する、悪魔的学習ステップ3選.pptx
 
論文紹介:Video-GroundingDINO: Towards Open-Vocabulary Spatio-Temporal Video Groun...
論文紹介:Video-GroundingDINO: Towards Open-Vocabulary Spatio-Temporal Video Groun...論文紹介:Video-GroundingDINO: Towards Open-Vocabulary Spatio-Temporal Video Groun...
論文紹介:Video-GroundingDINO: Towards Open-Vocabulary Spatio-Temporal Video Groun...
 
LoRaWANスマート距離検出センサー DS20L カタログ LiDARデバイス
LoRaWANスマート距離検出センサー  DS20L  カタログ  LiDARデバイスLoRaWANスマート距離検出センサー  DS20L  カタログ  LiDARデバイス
LoRaWANスマート距離検出センサー DS20L カタログ LiDARデバイス
 
Utilizing Ballerina for Cloud Native Integrations
Utilizing Ballerina for Cloud Native IntegrationsUtilizing Ballerina for Cloud Native Integrations
Utilizing Ballerina for Cloud Native Integrations
 
Amazon SES を勉強してみる その22024/04/26の勉強会で発表されたものです。
Amazon SES を勉強してみる その22024/04/26の勉強会で発表されたものです。Amazon SES を勉強してみる その22024/04/26の勉強会で発表されたものです。
Amazon SES を勉強してみる その22024/04/26の勉強会で発表されたものです。
 

これから Haskell を書くにあたって