有状态版本的地图(Haskell)

时间:2018-01-28 22:00:07

标签: haskell higher-order-functions

我刚学会了创建高阶函数,我想创建一个map函数,它能够改变应用于元组的函数,使该函数适用于该类型的列表。 (就像地图功能一样。) 我试图以这样的方式创建它:

statefulMap :: ((a,state) -> (b,state)) -> (([a],state) -> ([b],state))

我希望能够使用此功能创建一系列完整加法器,但我该如何创建此功能呢?

1 个答案:

答案 0 :(得分:6)

这实际上已经存在:我们可以使用state monad并使用map的{​​em> monadic 版本:mapM

例如,我们可以为完整加法器编写一个函数。在这里,我认为 state 是指前一个完整加法器生成的进位。

所以我们可以将全加器设为:

import Control.Monad.State.Lazy

fa :: (Bool, Bool) -> State Bool Bool
fa (a, b) = do
   ci <- get
   let d = a /= b
   put ((ci && d) || (a && b))
   return (ci /= d)

类型意味着我们创建一个改变状态的函数。第一个Bool指定状态本身的类型(这里是布尔值,进位是TrueFalse),第二个Bool指定我们“返回”的内容(这里有一个TrueFalse作为特定全加器的输出。)

现在我们可以使用mapM制作有状态地图:

fullAdders :: [(Bool, Bool)] -> State Bool [Bool]
fullAdders = mapM fa

这样就会得到一个2元组的列表(每个完整加法器的输入),并产生一个State Bool [Bool],所以状态仍然是Bool,但结果现在是一个列表布尔值[Bool]:包含每个完整加法器输出的列表。

我们现在可以使用fullAdders [(True, True), (True, False), (False, False), (True, True)]来调用它,但这将给我们一个布尔列表,但是State Bool [Bool]。我们可以通过指定初始状态来“运行”状态monad。我们可以使用runState :: State a b -> a -> (a, b)来完成此操作,因此我们可以通过以下方式调用它:

runState (fullAdders [(True, True), (True, False), (False, False), (True, True)]) False

这会产生:

Prelude Control.Monad.State.Lazy> runState (fullAdders [(True, True), (True, False), (False, False), (True, True)]) False
([False,False,True,False],True)

所以一个2元组作为第一项结果,第二项作为新状态(这里是True,因为最后一个全加器的进位输出将是True)。