Chaining State Monad

问题描述 投票:1回答:1

我有一个功能

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

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

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

例如,步骤如下

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

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
haskell monads state-monad
1个回答
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))

希望有所帮助

© www.soinside.com 2019 - 2024. All rights reserved.