関数指向でトップダウンに実装する
参考
関数型言語を最初にやったとき、「どうやったらこんなシンプルな実装思いつくんだ??」となった
『関数プログラミング実践入門』.iconの6章でそのやり方が具体的に解説されている
大雑把な流れ
実装する関数の仕様を確定する
関数のinput/outputの型を決定して書く
関数のinput/outputの型を考えて更に分解していく
標準関数レベルまで小さくなったら、組み合わせるなどをしていく
最初に型のみの関数を1つ作る
2つに分解する
4つに分解する
この辺で標準関数レベルの小ささになる
hoogleを使って型から関数を探す
undefined部分を実装する
組み合わせて2つにする
hlintの助けも借りて組み合わせられることに気付く
更に組み合わせて最終的に1行になる
code:hs
import Data.LIst (group)
rle :: String -> String
rle = concatMap (\s -> head s : show $ length s) . group
みたいな流れになっている
少しずつ分解していき、最後に組み合わせて、きれいな形に戻る
この流れはすごく良い
これらの標準的な関数をそもそも知っていれば、最初から書けるかもしれないが、
ポイントはそれを知らない人向けの方法が書かれてあること
型から考える、というのもポイント
Haskellではundefinedを使うことで実装を記述するのを保留できる
code:1つめ.hs
rle :: String -> String
rle = undefined
「型のみ書いて分解していく」ということができる
code:2つに分解.hs
rle :: String -> String
rle = fromCharAndRunLength . toCharAndRunLength
fromCharAndRunLength = undefined
toCharAndRunLength = undefined
code:更に分解.hs
rle :: String -> String
rle = fromCharAndRunLength . toCharAndRunLength
fromCharAndRunLength = cat . rls2strs
cat :: String -> String -- これは標準関数のconcatと同じである cat = undefined -- ということに調べて気付く
rls2strs = undefined
toCharAndRunLength = toPairs . toRLs
toPairs = undefined
toRLs = undefined
型を見て、実装が容易に想像できるぐらいまで小さくなれば、あとは型エラーが出ないように実装をしていけばいい
ある程度小さくなったらundefinedをけす
code:undefinedけす.hs
rle :: String -> String
rle = fromCharAndRunLength . toCharAndRunLength
fromCharAndRunLength = concat . rls2strs
rls2strs = map rl2str
rl2str :: (Char, Int) -> String
rl2str (c,n) = c : show n
toCharAndRunLength = toPairs . group
toPairs = map toPair
toPair :: String -> (Char, Int)
toPair s = (head s, length s)
この時点で、完成はしてる。ちゃんと動く
組み合わせて小さくしていく
code:組み合わせていく.hs
rle :: String -> String
rle = concat . map rl2str . map toPair . group
rl2str :: (Char, Int) -> String
rl2str (c,n) = c : show n
toPair :: String -> (Char, Int)
toPair s = (head s, length s)
するとhlintによりヒントが出るのでそれに従ってキレイにしていく https://gyazo.com/ceae83ec394dd1d35fec0b2ca00fa9bc
残り2つの関数も埋め込んじゃう
code:更に組み合わせる.hs
rle :: String -> String
rle = concatMap (\s -> head s : show (length s)) . group
完成
標準関数の組み合わせだけで実装できた。