連続投稿ですが、すごいH本を読みながら、ふとアイデアが湧いてきたのでHaskellコードを書きなぐってみた。
- 作者: Miran Lipovaca
- 出版社/メーカー: オーム社
- 発売日: 2012/09/21
- メディア: Kindle版
- 購入: 1人 クリック: 4回
- この商品を含むブログを見る
Functorは写像を作るための型クラス。写像とは単なるコピーではなく、何からの変換処理を意味するのですが、そのFunctorの題材としてなんかよいものないかなーと考えていたのですが、ページング処理でよく使う"ページ"をFunctorにすると便利じゃないか!と思ったので考えてみた。コードは次のとおり。
data Page a = EmptyPage | DefinedPage { items :: [a], pageNo :: Int, offset :: Int, total :: Int } deriving Show prev :: Page a -> Maybe Int prev EmptyPage = Nothing prev (DefinedPage _ p _ _) = if (p -1 > -1) then Just $ p - 1 else Nothing next :: Page a -> Maybe Int next EmptyPage = Nothing next (DefinedPage i p o t) = if (o + length i < t) then Just $ p + 1 else Nothing instance Functor Page where fmap f EmptyPage = EmptyPage fmap f (DefinedPage i p o t) = DefinedPage { items = map f i, pageNo = p, offset = o, total = t } main = do let defined = DefinedPage{ items = [1, 2, 3], pageNo = 1, offset = 0, total = 10 } let empty = EmptyPage let fmapPage1 = fmap (+1) defined let fmapPage2 = fmap (+1) empty putStrLn $ show(fmapPage1) ++ ", prev = " ++ show(prev fmapPage1) ++ ", next = " ++ show(next fmapPage1) putStrLn $ show(fmapPage2) ++ ", prev = " ++ show(prev fmapPage2) ++ ", next = " ++ show(next fmapPage2)
ざっと解説。 Pageは型引数を一つ取るページを表す独自データ型です。EmptyPageは空のページを表す。DefinedPageにはページ内のデータを表すitems, ページ番号のpageNo, オフセットのoffset, 全件数のtotalの属性を持っています。prev関数とnext関数はそのページの前後のページ番号を返します。
Page用のFunctor型クラスのインスタンス(実装)を定義。EmptyPageが来た時はEmptyPageを返し、DefinedPageの時は関数であるfをitemsにmapしその結果を保持する新たなDefinedPageを返します。
このFunctorインスタンスのおかげで、
*Main> fmap (+1) EmptyPage
EmptyPage
*Main> fmap (+1) DefinedPage { items = [1,2,3], pageNo = 1, offset = 1, total = 10 }
DefinedPage {items = [2,3,4], pageNo = 1, offset = 1, total = 10}
が可能になります。これは便利すぎる! というわけで、main部分の処理では、DefinedPageやEmptyPageを気にせずにfmapやってます。(mainの処理を関数に切り出したいな…)