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

为什么对[Maybe Integer]列表求和需要两次调用sum函数?

核心原因

你观察到的行为是Haskell的类型类重载和Functor实例共同作用的结果,分两点拆解:

  1. 你用到的fmap是列表类型的Functor实现
    fmap的通用类型是Functor f => (a -> b) -> f a -> f b,当你将fmap作用在类型为[Maybe Integer]的列表上时,这里的f就是列表类型,列表的fmap实现等价于普通的map函数。所以fmap sum (map square [1..64])本质是对列表里的每个Maybe Integer元素单独调用sum,而不是对整个列表求和。
  2. sum可以直接作用于Maybe类型
    sum的类型签名是(Foldable t, Num a) => t a -> a,它支持所有实现了Foldable类型类的容器作为入参,而Maybe是标准库中已经实现了Foldable的类型:
  • 当入参是Just x时,sum直接返回x
  • 当入参是Nothing时,sum返回Num类型的默认零值
    所以这一步fmap sum的效果就是把列表里的Maybe包装拆掉,Nothing转成0,Just值转成内部的整数,最终得到一个[Integer]类型的列表,你再对这个列表调用sum才能得到总和。

更优雅的复用写法

你原来的写法虽然能跑,但可读性一般,可以用更直观的方式拆包Maybe值再求和:

import Data.Maybe (maybe)

total :: Integer
total = sum $ map (maybe 0 id) $ map square [1..64]

因为你遍历的范围是明确合法的[1..64],也可以直接用等比数列求和公式复用square的边界逻辑,计算效率更高:

total :: Integer
total = case square 64 of
  Just v -> v * 2 - 1
  Nothing -> 0

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.06 21:06:00