Haskell如何为Array实现类似Prelude的scanl函数?能否用Traversable构建?
针对Array的scanl实现方案
首先,标准库Data.Array并没有直接提供和Prelude中scanl完全对应的函数,但你可以基于现有工具轻松实现,也能借助Traversable结合状态 monad 来构建。
直接基于base库实现
核心思路是先提取Array的有序元素列表,用Prelude的scanl处理后重新打包为Array:
import Data.Array (Array, bounds, elems, listArray) -- 符合你期望类型的scanl实现 scanlArray :: (Bar -> Foo -> Bar) -> Bar -> Array Int Foo -> Array Int Bar scanlArray f init arr = listArray (bounds arr) $ tail $ scanl f init (elems arr)
关键细节:
elems arr会按索引升序返回Array元素,保证扫描顺序是从左到右scanl f init (elems arr)生成包含初始值和每一步累积结果的列表,tail去掉初始值后,长度和原Array完全匹配listArray (bounds arr)用原Array的索引范围构建新Array,确保输出索引和输入一致
借助Traversable和State Monad构建
如果想用Traversable实现,可以结合State monad跟踪累积状态:
import Control.Monad.State (State, runState, get, put) import Data.Array (Array, bounds, elems, listArray) import Data.Traversable (traverse) scanlArrayTraversable :: (Bar -> Foo -> Bar) -> Bar -> Array Int Foo -> Array Int Bar scanlArrayTraversable f init arr = let step foo = do currentState <- get let nextState = f currentState foo put nextState return nextState (results, _) = runState (traverse step (elems arr)) init in listArray (bounds arr) results
实现逻辑:
- 用
Statemonad保存当前累积状态 traverse遍历Array的每个元素,每一步更新状态并记录当前结果- 最后将收集到的结果列表打包为Array,索引范围和原Array一致
注:Data.Array.Array是Traversable的实例,因此可以直接使用traverse遍历元素。
内容的提问来源于stack exchange,提问作者cdupont
相关产品推荐
相关产品推荐

