我刚学会了创建高阶函数,我想创建一个map函数,它能够改变应用于元组的函数,使该函数适用于该类型的列表。 (就像地图功能一样。) 我试图以这样的方式创建它:
statefulMap :: ((a,state) -> (b,state)) -> (([a],state) -> ([b],state))
我希望能够使用此功能创建一系列完整加法器,但我该如何创建此功能呢?
答案 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
指定状态本身的类型(这里是布尔值,进位是True
或False
),第二个Bool
指定我们“返回”的内容(这里有一个True
或False
作为特定全加器的输出。)
现在我们可以使用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
)。