みんなの知らない型の世界
Flatten編
自己紹介
名前
- 五十嵐 雄 (Twitter: @yu_i9 / GitHub: @yu-i9)
所属
- 京大情報学科計算機科学コース3回生
- CAMPHOR- 副代表
興味
- 型システム
Haskellでもflattenしたい!
突然ですが……
flatten :: [[a]] -> [a]
flatten = concat
そうじゃない
任意の深さのリストに対するflatten
Pythonで書くと……
def flatten(l):
result = []
for item in l:
if isinstance(item, list):
result.extend(flatten(item))
else:
result.append(item)
return result
Haskellでの難しさ
型シグネチャを書こうとすると分かる
flatten :: ??
flatten :: [[a]] -> [a]
flatten :: [[[a]]] -> [a]
flatten :: [[[[a]]]] -> [a]
...
これを一般化する道具が簡単には用意できない
解決の方針
[[a]], [[[a]]], [[[[a]]]], ...
つまり「リスト」という性質を持った
型の集合を表現する方法を考える
型クラス
ここで天下り
class Flatten i o where
flatten :: [i] -> [o]
instance Flatten a a where
flatten = id
instance Flatten i o => Flatten [i] o where
flatten = concatMap flatten
Prelude> flatten [[[1,2,3]]] :: [Int]
この時点で以下のような型は分かる
flatten :: [[[Int]]] -> [Int]
これにインスタンスをあてはめてみると
instance Flatten [Int] Int => Flatten [[Int]] Int where
flatten :: [[[Int]]] -> [Int]
flatten = concatMap flatten
Prelude> flatten [[1,2,3]] :: [Int]
次のインスタンスは以下のように続く
instance Flatten Int Int => Flatten [Int] Int where
flatten :: [[Int]] -> [Int]
flatten = concatMap flatten
concatMap で リストのネストが浅くなる
instance Flatten Int Int where
flatten :: [Int] -> [Int]
flatten = id
結局何をしているの
class Flatten i o where
flatten :: [i] -> [o]
- o が再帰の終了条件
- リスト型 i を o に一致するまで崩す
- 型に応じて正しい関数を選択する(flatten or id)
Flatten [[[Int]]] Int → Flatten Int Int
結論
型クラスは異なる型に対して共通の
インターフェースを定義するだけでなく,
型の再帰的な構造を表現するなど
たくさんの可能性を秘めている.
参考資料(元ネタ)
Is there a function to flatten a nested list of elements?
http://stackoverflow.com/questions/5994051/is-there-a-function-to-flatten-a-nested-list-of-elements
現実的な解
flatten :: [[a]] -> [a]
flatten = concat
flatten2 :: [[[a]]] -> [a]
flatten2 = concatMap concat
flatten3 :: [[[[a]]]] -> [a]
flatten3 = concatMap flatten2
flatten4 :: [[[[[a]]]]] -> [a]
flatten4 = concatMap flatten3
flatten5 以上を使う奴を殺す
質疑応答
Flatten
By Yuu Igarashi
Flatten
- 1,194