Haskell でStackを(3)
今度はスタックのサイズは固定、要素もIntのみで、状態モナドを止めてみた。スタック自身でポインタを管理する。これで複数のスタックを使える。ほぼCの構造体になったと思うがわたしはCを書けないので自信なし。
import Foreign.Ptr import Foreign.Marshal.Alloc import Foreign.Marshal.Array import Foreign.Storable stackSize :: Int stackSize = 20 -- スタックのインデックスとスタック本体へのポインタ data Stack = Stack Int (Ptr Int) deriving Show instance Storable Stack where alignment _ = 16 sizeOf _ = 16 peek ptr = do n <- peek (castPtr ptr) p <- peek (castPtr ptr `plusPtr` 8) return $ Stack n p poke ptr (Stack n p) = do poke (castPtr ptr) n poke (castPtr ptr `plusPtr` 8) p mkStack :: IO (Ptr Stack) mkStack = do p <- malloc :: IO (Ptr Stack) s <- mallocArray stackSize poke p (Stack 0 s) return p push :: Ptr Stack -> Int -> IO (Ptr Stack) push st x = do Stack i p <- peek st if i >= stackSize then error "oops. Stack overflow" else do pokeElemOff p i x poke st (Stack (i + 1) p) return st pop :: Ptr Stack -> IO Int pop st = do Stack i p <- peek st if i <= 0 then error "oops. Stack underflow" else do x <- peekElemOff p (i - 1) poke st (Stack (i - 1) p) return x calc :: (Int -> Int -> Int) -> Ptr Stack -> IO (Ptr Stack) calc f st = do x <- pop st y <- pop st push st (f x y) add :: Ptr Stack -> IO (Ptr Stack) add = calc (+) sub :: Ptr Stack -> IO (Ptr Stack) sub = calc (-)
使い方はこのように変わる。
test0 = do st <- mkStack push st 9 pop st