みんなの知らない型の世界

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

結論

型クラスは異なる型に対して共通の

インターフェースを定義するだけでなく,

型の再帰的な構造を表現するなど

たくさんの可能性を秘めている.

参考資料(元ネタ)

現実的な解

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,094