Free Monadで料理を記述する
ここ数日、Why free monads matterの記事を読んでいました。
非常に簡単にモナドを構成できるのはわかったけれど、
これで何が嬉しいのかよくわかりませんでした。
で、記事を読み進めていくうちに、手続き自体の構造を記述するのに非常に便利なのではないか、それなら料理のレシピとか記述できそう!
料理をモナドにすることの何が嬉しいかって、
記述時に、do記法を使って非常に直感的に書けるじゃん!
と、ただそれだけの理由で作ってみた。
今回は卵焼きを作ってみた。
まずは必要なデータを用意。
調理器具と食材はユーザーが自由に設定出来るよう、Stringとしました。
加熱には時間と調理器具(今気づいたけど、食材でもいいですね)と火力、
焼く・混ぜる作業には食材群が必要です。
また、レシピモナドであることを明確にするため、RecipeTを定義します。
--食材 type Ingredient = String --火力 data Power = Low | Medium | Strong deriving Show --調理器具 type Cookware = String data Cook next = Heat Int Power Cookware next | Mix [Ingredient] next | Bake Int [Ingredient] next | Done type RecipeT = FreeT Cook
そしてこいつを、Functorのインスタンスにします
instance Functor Cook where fmap f (Heat n p ware next) = Heat n p ware (f next) fmap f (Mix ings next) = Mix ings (f next) fmap f (Bake n ings next) = Bake n ings (f next) fmap f Done = Done
次に、調理方法を関数として実装します
bake :: Monad m => Int -> [Ingredient] -> RecipeT m () bake n ings = liftF (Bake n ings ()) mix :: Monad m => [Ingredient] -> RecipeT m () mix ings = liftF (Mix ings ()) heat :: Monad m => Int ->Power -> Cookware -> RecipeT m () heat n pw ware = liftF (Heat n pw ware ()) done :: Monad m => RecipeT m () done = liftF Done
では実際に卵焼きのレシピを作成しましょう!!
熱した鍋に溶いた卵をいれて焼けばいいですよね
omelet :: Monad m => RecipeT m () omelet = do let egg = ["egg"] mix egg heat 2 Strong "pan" bake 3 egg done
と、このように!
非常に直感的に書けるようになりました!パチパチー