您可以使用一些标准功能来满足您的要求。
听起来很像你想要mapAccum,所以你只需要导入Data.List 并决定你要累积的方式。 (我怀疑你想要mapAccumL :: (acc -> x -> (acc, y)) -> acc -> [x] -> (acc, [y])。)
mapAccumL
import Data.List
data Instruction = NoChange | Reset | MoveBy Int
tell :: Int -> Instruction -> (Int,String) -- toy accumulating function
tell n NoChange = (n,"")
tell n Reset = (0,"Reset to zero")
tell n (MoveBy i) = (n+i,"Add "++show i++" to get "++ show (n+i))
这会给
ghci> mapAccumL tell 10 [MoveBy 5, MoveBy 3, NoChange, Reset, MoveBy 7]
(7,["Add 5 to get 15","Add 3 to get 18","","Reset to zero","Add 7 to get 7"])
扫描L
但也许您不需要使用mapAccum 的全部功能,因为有时累加器就是您想要的新列表,所以scanl :: (a -> b -> a) -> a -> [b] -> [a] 可以解决问题
act :: Int -> Instruction -> Int
act n NoChange = n
act n Reset = 0
act n (MoveBy i) = n+i
像这样:
ghci> scanl act 10 [MoveBy 5, MoveBy 3, NoChange, Reset, MoveBy 7]
[10,15,18,18,0,7]
mapAccum 的定义
不管怎样,mapAccumL 和 mapAccumR 在Data.List 中是这样描述的:
mapAccumL :: (acc -> x -> (acc, y)) -> acc -> [x] -> (acc, [y])
mapAccumL _ state [] = (state, [])
mapAccumL f state (x:xs) = (finalstate,y:ys)
where (nextstate, y ) = f state x
(finalstate,ys) = mapAccumL f nextstate xs
mapAccumL 函数的行为类似于map 和foldl 的组合;它将一个函数应用于列表的每个元素,从左到右传递一个累加参数,并将这个累加器的最终值与新列表一起返回。
mapAccumR :: (acc -> x -> (acc, y)) -> acc -> [x] -> (acc, [y])
mapAccumR _ state [] = (state, [])
mapAccumR f state (x:xs) = (finalstate, y:ys)
where (finalstate,y ) = f nextstate x
(nextstate, ys) = mapAccumR f state xs
mapAccumR 函数的行为类似于map 和foldr 的组合;它将一个函数应用于列表的每个元素,从右到左传递一个累加参数,并将该累加器的最终值与新列表一起返回。