読者です 読者をやめる 読者になる 読者になる

りんごがでている

何か役に立つことを書きます

一体何番煎じか分かったもんじゃないけどMonadでStack (2)

Haskell

前回の記事で作製した

data Stack a = Stack a (Stack a) | Empty deriving (Show)
type MonadStack a = State (Stack a) a

で問題が発覚したから、ちゃんと直しましょう。名だたるHaskeller達に噴飯されないように。せめて失笑レベルまで持って行きたいな。


型変数追加

で何が問題かって言うと、MonadStackの型変数がaだけでStackに押し込む値の型も、MonadStackの操作で返る値の型も同じaだってこと。
じゃ、それぞれに別々の型変数を用意すればイイね。ってことで型変数bをMonadStackに追加で。

data Stack a = Stack a (Stack a) | Empty deriving (Show)
type MonadStack a b = State (Stack a) b

これでOK。あとは実装した関数たちの型も変更してやれば大丈夫ですな(ノ´∀`*)

push :: a -> MonadStack a a
pop :: MonadStack a a
top :: MonadStack a a
empty :: MonadStack a Bool
size :: MonadStack a Int

(*実装省略)


> runState (push 1 >> empty) Empty
(False,Stack 1 Empty)
> runState (empty) Empty
(True,Empty)

やったぜワッショイ(∩´∀`)∩ワーイ


ついでにfoldとfmapも…

Stackに対するfoldrとfmapも定義してみよう。

import Prelude hiding (foldr)

instance Foldable Stack where
    foldr f z Empty = z
    foldr f z (Stack x stack) = foldr f (f x z) stack

instance Functor Stack where
    fmap f Empty = Empty
    fmap f (Stack x stack) = Stack (f x) (fmap f stack)


よし。そしてMonadStack用にmapSとfoldSも作ったぞ。役に立つかは知りません。

mapS :: (a -> b) -> MonadStack a (Stack b)
mapS f = do
    stack <- get
    return $ fmap f stack

foldS :: (a -> b -> b) -> b -> MonadStack a b
foldS f x = do
    stack <- get
    return $ foldr f x stack

とまぁこんな感じでStackをMonadで扱えるようにしてみた。
せっかくだから何かに使いたいな〜なんて思ったりしている(´・ω・`)