Haskell ã§åçè¨ç»æ³ãæ¸ãããã®3ã¤ã®æ¹é
ã¢ã«ã´ãªãºã ã®ä»£è¡¨ã£ã½ãåå¨ã¨ãè¨ããDPã§ããï¼Haskellã¯åç
§éæãªã®ã§æ¸ãã«ããã¨æãããã¡ã§ãï¼
ãããï¼å®éã¯ï¼Cè¨èªãSTLãªãã®C++ããé¥ãã«ç°¡åã«åçè¨ç»æ³ãæ¸ãã¾ãï¼
ãªã¹ããç¨ãã
æåã«ç¥ãã§ãããæ¹æ³ï¼
ãã£ããããæ°åã®ç¬¬100é
ã ã¨ï¼
let f = 0 : 1 : zipWith (+) a (tail a) in f!!100
ã§ãï¼
ããããã¦è¶³ãããã®ãå¾ãã«ã¤ãªãããã¨è¨ãã°ããã®ã§ããããï¼
ããã«ã¤ãã¦ã¯ï¼ä»ã§ãã解説ããã¦ããã®ã§è©³ããã¯èª¬æãã¾ããï¼
å©ç¹ï¼
- ãªã¹ãã®ç¥èã®ã¿ã§ããï¼
- ç¡éãªã¹ãã®æ©æµãåããããï¼
- importãä¸è¦ï¼
æ¬ ç¹ï¼
- 使ããã±ã¼ã¹ãéãããï¼
- æ¸ãã¨ãã«ï¼æ··ä¹±ãããã¨ãï¼ä¸ã®ä¾ã ã¨ï¼ã¨èããå¿ è¦ãããï¼
- ã©ã³ãã ã¢ã¯ã»ã¹ãã§ããªãã®ã§ï¼å ´åã«ãã£ã¦ã¯O(n)åã®æéãããã*1ï¼
æ·»åãèªç±ã«ç¨ãããã¨ãã§ããªãã®ã§ï¼ãã ã®ãHaskellã§ãã£ããããæ°ã楽ã«ããããã¨ãã宣ä¼ãããã«ãã使ããªãããããã¾ããï¼
Arrayãç¨ãã
æ·»åãç¨ãã¦åç §ãããã¨ãã«å½¹ç«ã¤æ¹æ³ï¼
import Array let f = array (0,100) ((0,0):(1,1):[(k, f!(k-2)+f!(k-1))| k<-[2..100]]) in f!100
ã¨æ¸ããã®ã§ããï¼è¦ã¯ï¼ã¨å®ç¾©ã並ã¹ãã ãã§ããã¨ãããã¨ã§ãï¼
å¤æ°ã101åä½ãï¼ä¾åé¢ä¿ã¯Haskellã«ä»»ããããã¨èããã¨ããã®ããç¥ãã¾ããï¼
é 延è©ä¾¡ã®ãããã§ï¼
import Array let f = array (0,200) ((0,0):(2,1):[(k, f!(k-4)+f!(k-2))| k<-[4,6..200]]) in f!200
ã¨ä½¿ããªãæ·»åããã£ã¦ãã¡ããã¨åä½ãã¾ã*2ãï¼
import Array let f = array (0,100) ((1,1):(0,0):reverse [(k, f!(k-2)+f!(k-1))| k<-[2..100]]) in f!100
ã®ããã«ï¼åæ·»åã®å¤ã®å®ç¾©ãæ¸ãé çªãå¤ãã¦ãåä½ãã¾ã*3ï¼
å©ç¹ï¼
- æ®éã®DPãªãã»ã¨ãã©æ¸ããï¼
- å®ç¾©ã並ã¹ãã ãã§æ¸ããï¼
æ¬ ç¹ï¼
- Arrayãããï¼
- è¨ç®ã«å¿ è¦ãªæ·»åã®ç¯å²ãç¥ã£ã¦ããå¿ è¦ãããï¼
Stateã¢ãããç¨ãã
Arrayãç¨ããå ´åã¯æ·»åã®ç¯å²ããããããå®ããªããã°ãªãã¾ãã*4ï¼
ããã¯æç¶ãåè¨èªã§æ¸ããæã«é
åã®å¤§ããã決ããªããã°ãªããªãã¨ããåé¡ã«å¯¾å¿ãï¼ããããæã¯é£æ³é
åã使ããã¨ãå®ç³ã§ãï¼
ãã¦ï¼Haskellã§ã©ã®ããã«æ¸ãã°ãããã¨ããã¨ï¼è¨ç®ä¸ã«çããèããé£æ³é
åãæã¡ã¾ããã¨ãããç¶æ
ã¤ãè¨ç®ããè¡ããã¨ã«ãªãã®ã§ï¼Stateã¢ãããç¨ãããã¨æ¥½ã«æ¸ãã¾ãï¼
åèURLï¼
- http://www.sampou.org/haskell/a-a-monads/html/statemonad.html
- http://www.haskell.org/ghc/docs/5.04.3/html/base/Control.Monad.State.html
Stateã¢ãããghc6ããæ¨æºã§ã¯ä»å±ãã¦ããªããããªã®ã§ï¼æ¥è¨ã®æå¾ã«é©å½ãªç§ã®å®è£ ãè¼ãã¦ããã¾ãï¼
ã¾ãï¼DPãããããã®ã©ã¤ãã©ãªã¯ãããªæãã§ãï¼ghcåãï¼ï¼
-- DP.hs module DP ( DP , dp , evalDP, evalDPAll ) where import qualified Data.Map import State -- ããã¯ç°å¢ã«å¿ãã¦é©åã«æ¸ãæãã¦ãã ããï¼ type Memo a b = Data.Map.Map a b type DP a b = a -> State (Memo a b) b emptyMemo :: Memo a b emptyMemo = Data.Map.empty lookupMemo :: Ord a => a -> Memo a b -> Maybe b lookupMemo = Data.Map.lookup insertMemo :: Ord a => a -> b -> Memo a b -> Memo a b insertMemo = Data.Map.insert dp :: Ord a => DP a b -> DP a b dp f x = do memo <- gets (lookupMemo x) case memo of Just y -> return y Nothing -> do y <- f x modify (insertMemo x y) return y evalDP :: DP a b -> a -> b evalDP f x = evalState (f x) emptyMemo evalDPAll :: DP a b -> [a] -> [b] evalDPAll f xs = evalState (sequence (map f xs)) emptyMemo
ç´°é¨ãçãã¦èª¬æããã¨ï¼DP a bã¨ããã®ãï¼åaããåbã¸ã®ã¡ã¢åå帰ãããé¢æ°ã®åã§ãï¼
ã¡ã¢ç¨ã®é£æ³é
åã«ã¯Data.Mapã¨ãããã©ã³ã¹æ¨ãç¨ãï¼dpã¯ï¼é¢æ°ãåãåããå¼æ°ãlookupãã¦ã¡ã¢ã«ããã°ãããè¿ãï¼ãªããã°ï¼è¨ç®ãã¦çµæãinsertãã¤ã¤è¿ããã¨ããæ°ããé¢æ°ãè¿ãã¾ãï¼
evalDPã¯ç©ºã®ã¡ã¢ããå®è¡ãã¦çµæãè¿ãé¢æ°ï¼
evalDPAllã¯ãã®è¤æ°ã®å¼æ°ã§ã¡ã¢ã使ãåãã¦å®è¡ãããã¼ã¸ã§ã³ã§ãï¼
使ãæ¹ã¯ï¼
fib :: Int -> Integer fib = evalDP fib' fib' :: DP Int Integer fib' = dp $ \ n -> if n <= 1 then return (toInteger n) else do a <- fib' (n-2) b <- fib' (n-1) return (a+b)
ã®ããã«ï¼é¢æ°å®ç¾©ã«dpãæãã ãï¼
ã¨ããã¨ï¼å°ãè¨ãéãã§ï¼ã¢ãããªã®ã§ï¼returnã¨ãdoã¨ã*5æ¸ãå¿
è¦ãããã¾ãï¼
å®éï¼å帰å¼ã³åºãã®é åºãç°ãªãã¨ç°ãªãè¨ç®ã«ãªã*6ã®ã§ï¼ãã®å¶ç´ã¯åé¿ä¸å¯è½ã§ãï¼
å©ç¹ï¼
- ã¨ããããä¸è½ï¼
æ¬ ç¹ï¼
- æ¯åã©ã¤ãã©ãªãæã§æ¸ãã®ã¯é¢å*7ï¼
ä¾é¡
Problem 14 - Project Euler
ã100ä¸æªæºã®æ°ããå§ãã¦ï¼ã³ã©ããäºæ³ã®æ°åãä½ãã¨ãï¼1ã«ãªãã¾ã§ã®ã¹ããããæãé·ãã®ã¯ï¼ã
ã®è§£çï¼
import DP main = print . solve $ 10^6 - 1 solve nMax = snd . maximum . flip zip [1..] . evalDPAll collatzLength $ [1..nMax] collatzLength :: DP Integer Int collatzLength = dp $ \ n -> if n == 1 then return 0 else do l <- collatzLength (collatzIter n) return $ l + 1 collatzIter :: Integer -> Integer collatzIter n = if even n then n`div`2 else 3*n+1
Stateã¢ããå®è£ ä¾
-- State.hs module State ( State , runState , get, put , modify, gets , evalState, execState ) where newtype State s a = State { runState :: (s -> (a,s)) } instance Monad (State s) where return a = State $ \ s -> (a,s) (State x) >>= f = State $ \ s -> let (v,s') = x s in runState (f v) s' get :: (State s) s put :: s -> (State s) () get = State $ \ s -> (s,s) put s = State $ \ _ -> ((),s) modify :: (s -> s) -> (State s) () modify f = get >>= put . f gets :: (s -> a) -> (State s) a gets f = get >>= return . f evalState :: State s a -> s -> a evalState = (fst .) . runState execState :: State s a -> s -> s execState = (snd .) . runState
*1:æéãããã£ã¦ãè¯ãããæ¸ãããã¨è¨ãããã¨å°ãèªä¿¡ãããã¾ãã
*2:ãã ãï¼ã¡ã¢ãªã¯æ¶è²»ãã¾ã
*3:ã¡ãªã¿ã«ï¼åãæ·»åã2å以ä¸æ¸ãã¨ghcã§ã¯æå¾ã®ãç¨ãããï¼æ¬å½ã¯undefinedããã
*4:ãªã¹ãã ã¨ããããèªåãã大ããæ·»åãåç §ã§ããªã
*5:liftM2ãç¨ããæ¹ã楽ã«æ¸ããã¨ãã人ã¯ããã§ãOK
*6:ã¡ã¢ãããé çªãç°ãªãï¼æ¨ã®ç´°é¨ãç°ãªã£ã¦ãã
*7:ã¤ã¾ãï¼ãæã¡è¾¼ã¿å¯ã®è©¦é¨ãã«éããã