Chaining State Monad

时间:2017-08-01 10:53:06

标签: haskell monads state-monad

我有一个功能

step :: Int -> State Int Int
step n = get >>= \x ->  put  (x `div` n) >> return (x `mod` n)

λ> runState (step 25) 41
(16,1)

如何使用step的不同值运行n s序列,并使用上一步中的状态执行每个步骤?

所以例如步骤如下

第一步产生(16,1),然后我想将其用作n = 10的下一步的输入,这应该产生(6, 2)。将第一步中的1添加到第一步中,将第一步中的16添加为新的n。

n = 25 gives (16,1) then
n = 10 gives (6,2)  then
n = 5  gives (1,3) then
n = 1 gives (0,4)

我知道在这里使用State可能不正确;但我试图用它来学习。

可能的目的是用状态monad实现这个功能。

greedy :: Double -> Int
greedy owed = snd $ foldl go (pennies,0) [25, 10, 5, 1]
  where
    pennies                     = floor . (*100) $ owed
    go (remaining,counter) coin = (remaining',counter')
      where
        remaining' = remaining `mod` coin
        counter'   = counter + remaining `div` coin

1 个答案:

答案 0 :(得分:4)

功能,

mapM step [25,10,5,1]

或更一般的

traverse step [25,10,5,1]

step的每个列表上运行[25,10,5,1]。调用

runState  (mapM step [25,10,5,1]) 41

运行初始状态设置为41的函数,返回步骤输出列表和最终状态。

([16,1,0,0],0)

如果要列出状态以及输出,只需修改step以包含它们。

step n = get >>= \x ->  put  (x `div` n) >> return ((x `mod` n),(x `div` n))

或换句话说

step n = do 
  x <- get
  let (r,x') = (x `mod` n,x `div` n)
  put  x'
  return (r,x')

结果是([(16,1),(1,0),(0,0),(0,0)],0),仍然不是你想要的,但更接近。我恐怕我不能很好地理解你的等式的细节以获得你想要的东西,但这应该有助于理清状态部分,让你专注于数学。

制作上述go功能:

go n = do
   (r,c) <- get
   let (r',c') = (r `mod` n, c + (r `div` n))
   put (r',c')
   return (r',c')

runState (mapM go [25,10,5,1]) (41,0)

产量,

([(16,1),(6,2),(1,3),(0,4)],(0,4))

希望有所帮助