You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

实现逻辑:

  • 用State monad保存当前累积状态
  • traverse遍历Array的每个元素,每一步更新状态并记录当前结果
  • 最后将收集到的结果列表打包为Array,索引范围和原Array一致

注:Data.Array.Array是Traversable的实例,因此可以直接使用traverse遍历元素。

内容的提问来源于stack exchange,提问作者cdupont

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.17 02:40:35