我试图通过Project Euler来自学Haskell(再次)。问题14(https://projecteuler.net/problem=14)正在乞求动态编程,而且历史上我一直强烈反对monad(由于反复未能学会使用它们以使生活更轻松而不是更难)所以我&# 39;我试图咬紧牙关并使用State monad来记忆我的代码......它进展不顺利。我想清楚,我已经解决了这个简单/缓慢的问题,此时我正试图学习一些东西(即Project Euler No. 14 Haskell不是我想要的东西)。
到目前为止我的代码是:
collatzMemoCheck :: Int -> State (Map Int Int) Int
collatzMemoCheck n = state $ \s -> maybe (let (a, s') = runState (collatzFast n) s
in (a+1, Map.insert n (a+1) s'))
(\len -> (len, s))
(Map.lookup n s)
collatzFast :: Int -> State (Map Int Int) Int
collatzFast 1 = state $ \_ -> (1, Map.singleton 1 1)
collatzFast n
| even n = collatzMemoCheck (n `quot` 2)
| otherwise = collatzMemoCheck (3 * n + 1)
适用于cabal repl中的个别查询,但对于我的生活,我无法弄清楚如何将重复调用的状态链接到collatzFast。我想要像
这样的东西-- DOES NOT WORK
allCollatzLengths = scanl (>>= collatzFast) (return Map.empty) [1..999999]
但我认为这是内在的。 Bind获取前一个State计算的结果部分并将其传递给下一个调用,但我希望它获取前一个State计算的状态部分并将 it 传递给下一个调用。
有没有正确的方法可以做到这一点,还是我把自己画成角落?如果我不能使用>> =,那么拥有monad是什么意思? ......或者没有意义,因为这是一种愚蠢的做法?帮助
答案 0 :(得分:6)
你可能喜欢
mapM :: Monad m => (a -> m b) -> [a] -> m [b]
特别是mapM collatzFast :: [Int] -> State (Map Int Int) [Int]
。