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

为何无法用scanr替代scanl?Haskell函数调用报错排查

关于Haskell中scanl与scanr调用的类型错误问题

正常运行的scanl调用

使用scanl搭配flip(:)可以正常执行并得到结果:

ghci> scanl (flip(:)) [] [3,2,1]
[[],[3],[2,3],[1,2,3]]

使用scanr时的类型错误

改用scanr调用相同参数时,出现如下类型匹配错误:

ghci> scanr (flip(:)) [] [3,2,1]
<interactive>:129:8: error:
    • Couldn't match type ‘a’ with ‘[a]’
      Expected: [[a]] -> [a] -> [a]
        Actual: [[a]] -> [a] -> [[a]]
    • In the first argument of ‘scanr’, namely ‘(flip (:))’      
      In the expression: scanr (flip (:)) [] [3, 2, 1]
      In an equation for ‘it’: it = scanr (flip (:)) [] [3, 2, 1]
    • Relevant bindings include
        it :: [[a]] (bound at <interactive>:129:1)

问题核心

scanl和scanr对传入的二元函数参数顺序要求完全相反:

  • scanl的类型定义:(b -> a -> b) -> b -> [a] -> [b],二元函数需要先接收累积值(b类型),再接收列表元素(a类型),最终返回新的累积值(b类型)。
  • scanr的类型定义:(a -> b -> b) -> b -> [a] -> [b],二元函数需要先接收列表元素(a类型),再接收累积值(b类型),最终返回新的累积值(b类型)。

(:)的原生类型是a -> [a] -> [a],flip(:)将其参数反转成[a] -> a -> [a],刚好匹配scanl对二元函数的参数顺序要求(累积值是[a],列表元素是a)。但放到scanr中时,flip(:)的参数顺序和scanr的要求完全相反,导致类型推导失败,触发错误。

修改方案

不需要使用flip(:),直接用原生的(:)就能匹配scanr的参数顺序:

ghci> scanr (:) [] [3,2,1]
[[1,2,3],[2,3],[3],[]]

如果一定要保留flip的使用逻辑,需要调整二元函数的适配方式,但直接使用(:)是最简洁的解决办法——scanr从右往左遍历列表元素,(:)将元素添加到累积列表的头部,最终得到从最右侧元素开始逐步构建的列表序列。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 16:37:27