{- Table をキーと対応する値でパラメータ化する -} type Table k v = [(k,v)] emptyTable :: Table a b lookupTable :: Ord k => k -> Table k v -> [v] insertTable :: Ord k => k -> v -> Table k v -> Table k v emptyTable = [] lookupTable key [] = [] lookupTable key ((k,v):tbl) | key > k = [] | key == k = [v] | key < k = lookupTable key tbl insertTable k v tbl = case break ((k >) . fst) tbl of (xs,ys) -> xs ++ (k,v):ys {- memocc :: (Amount,[Coins]) -> Table Amount Count -> (Count,Table Amount Count) memocc (0,_ ) tbl = (1,tbl) memocc (_,[]) tbl = (0,tbl) memocc arg@(a,ccs@(c:cs)) tbl | a < 0 = (0,tbl) | otherwise = case lookupTable arg tbl of (v:_) -> (v,tbl) [] -> let (cnt1,tbl1) = memocc (a-c,ccs) tbl (cnt2,tbl2) = memocc (a , cs) tbl1 cnt3 = cnt1 + cnt2 tbl3 = insertTable arg cnt3 tbl2 in (cnt3,tbl3) evalMemoCC :: Amount -> [Coin] -> Count evalMemoCC amount coins = fst (memocc (amount,coins) emptyTable) -} {- 関心のあるデータ(\texttt{t}型)とは別に,変化する状態(\texttt{s}型)を 次へと伝えていく仕組み -} type State s t = s -> (t,s) withState :: t -> State s t withState x = \ state -> (x,state) bindState :: State s t -> (t -> State s u) -> State s u bindState sx sf s0 = let (x,s1) = sx s0 in sf x s1 evalState :: State s t -> s -> t evalState s s0 = fst (s s0) fun1WithState :: (a -> b) -> State s a -> State s b fun1WithState f sx = bindState sx (\ x -> withState (f x)) fun2WithState :: (a -> b -> c) -> State s a -> State s b -> State s c fun2WithState f sx sy = bindState sx (\ x -> bindState sy (\ y -> withState (f x y))) {- 高階関数 memoise -} memoise :: Ord a => (a -> State (Table a b) b) -> a -> State (Table a b) b memoise f x tbl = case lookupTable x tbl of y:_ -> (y,tbl) [] -> let (y,tbl') = f x tbl in (y,insertTable x y tbl') {- memocc (0,_ ) = withState 1 memocc (_,[]) = withState 0 memocc arg@(a,_) | a < 0 = withState 0 | otherwise = memoise (\ (a,ccs@(c:cs)) -> memocc (a-c,ccs) `add` memocc (a,cs)) arg where add = fun2WithState (+) -} instance Num b => Eq (State (Table a b) b) where sx == sy = (evalState sx emptyTable) == (evalState sy emptyTable) instance Num b => Show (State (Table a b) b) where show sx = show (evalState sx emptyTable) instance Num b => Num (State (Table a b) b) where (+) = fun2WithState (+) (-) = fun2WithState (-) (*) = fun2WithState (*) negate = fun1WithState negate abs = fun1WithState abs signum = fun1WithState signum fromInteger = withState . fromInteger type Amount = Integer type Coin = Integer type Count = Integer type Memo a b = (a -> State (Table a b) b) memocc :: Memo (Amount,[Coin]) Count memocc (0,_ ) = 1 memocc (_,[]) = 0 memocc arg@(a,_) | a < 0 = 0 | otherwise = memoise (\ (a,ccs@(c:cs)) -> memocc (a-c,ccs) + memocc (a,cs)) arg evalMemoCC :: Amount -> [Coin] -> Count evalMemoCC amount coins = evalState (memocc (amount,coins)) emptyTable