関数型プログラミングの考え方を理解するための昔の記事
この前
関数型プログラミングはまずは純粋関数型言語を用いて、考え方から理解しよう
関数型プログラミングはまず考え方から理解しよう - Qiita
ここを読んだ。
関数型プログラミングの考えを学ぶには、純粋関数型言語で学ぶべきである
これは同意なんだけど、サンプルコードがしっくり来ない。
こんなに複雑になる?というかオブジェクト指向のコードを関数型っぽく変換ということに無理があるような。
仕様を満たすコードをゼロから考えたら、全然変わってくるような。
ということでちょっとHaskellで書いてみた。
data Dish = Karaage deriving Eq data Bento = Bento Dish Int deriving Eq
単純な数値のリストかタプルでもいいんだけど、オブジェクト指向に寄せてデータ構造を書く。
eat :: Bento -> Bento eat (Bento s a) = Bento s (a - 1) replaceList :: Bento -> [Bento] -> [Bento] replaceList m a = replace a where replace [] = [] replace (x:xs) | m == x = eat x:xs | otherwise = x:replace xs
「データを1減らす」という処理と「リストを一つ入れ替える」という処理を書く。
「リストから最大のものを1件探す」という処理は maximumが使えるので、そのまま使う。
それからユーティリティ的な関数、「xに関数fをn回適用した結果を返す」を作る。
nest :: (a -> a) -> a -> Int -> a nest f x n = (iterate f x) !! n
最後に
bentoList :: [Bento] bentoList = [Bento Karaage 10, Bento Karaage 8, Bento Karaage 6] main :: IO () main = putStrLn $ show $ nest (maximum >>= replaceList) bentoList 5
一気に関数を接続して、計算。
※ n回繰り返したときの処理ログが欲しいわけではなく、最後の結果が欲しいということだと読み取ったので、途中経過は出力しない。
関数型プログラミングっていうかHaskell独自のことかもしれないけど、とりあえず細かい関数のパーツを作っておいて、繋ぎ合わせて大きな機能を作るのが関数型プログラミングの考え方っぽいと思える。
昔見たブログのやり取りはとても良かった。
Haskell でグローバル変数が欲しい理由 - あどけない話
グローバル変数が欲しい理由? (http://web.archive.org/web/20100702191552/http://www.sampou.org/cgi-bin/haskell.cgi?%A5%B0%A5%ED%A1%BC%A5%D0%A5%EB%CA%D1%BF%F4%A4%AC%CD%DF%A4%B7%A4%A4%CD%FD%CD%B3%A1%A9 )
「グローバル変数が欲しい理由?」の考察 - あどけない話
URLが変わっちゃったので再度メモ。
以下全体のコード。
module Main where data Dish = Karaage deriving Eq data Bento = Bento Dish Int deriving Eq instance Show Dish where show Karaage = "唐揚げ" instance Show Bento where show (Bento a b) = show a ++ show b ++ "個" instance Ord Bento where compare (Bento Karaage a) (Bento Karaage a') = compare a a' nest :: (a -> a) -> a -> Int -> a nest f x n = (iterate f x) !! n eat :: Bento -> Bento eat (Bento s a) = Bento s (a - 1) replaceList :: Bento -> [Bento] -> [Bento] replaceList m a = replace a where replace [] = [] replace (x:xs) | m == x = eat x:xs | otherwise = x:replace xs bentoList :: [Bento] bentoList = [Bento Karaage 10, Bento Karaage 8, Bento Karaage 6] main :: IO () main = putStrLn $ show $ nest (maximum >>= replaceList) bentoList 5