Maybe类型中fmap双参函数传入Nothing为何未返回Nothing反而报错?
为什么
fmap (++) Nothing报错而不是返回Nothing? 这个问题其实是个典型的「看起来结果不对,实则是类型打印卡壳」的小坑,我来给你拆解得明明白白:
核心真相:你其实已经得到了Nothing,只是它没法被打印出来
先回忆Functor的fmap类型签名:
fmap :: (a -> b) -> f a -> f b
咱们一步步拆解类型推导:
(++)的类型是[x] -> [x] -> [x],可以把它看成接受一个列表,返回另一个函数——也就是(++) :: [x] -> ([x] -> [x]),这里的a就是[x],b就是([x] -> [x])。Nothing属于Maybe [x](因为fmap要求f a里的a要和前面的a匹配,也就是[x])。- 所以
fmap (++) Nothing的结果必然是Nothing :: Maybe ([x] -> [x])——没错,它就是你预期的Nothing!
那为什么会报错?因为GHCi默认会尝试打印你执行的表达式结果,而([x] -> [x])是个函数类型,Haskell的标准库并没有给函数类型实现Show实例(毕竟函数没法直接转换成可读的字符串),所以GHCi没法把这个Nothing打印出来,才抛出了那个关于No instance for (Show ([a0] -> [a0]))的错误。
对比fmap (+1) Nothing能正常打印的原因
(+1)的类型是Num a => a -> a,这里的b是数值类型(比如Int、Integer),这些类型都有标准的Show实例,所以fmap (+1) Nothing的结果Nothing :: Maybe Int可以被正常打印出来。
验证一下这个结论
你可以在GHCi里试试这两个操作:
- 先绑定变量不打印:
let res = fmap (++) Nothing,这时候不会报错,因为只是定义变量,不需要打印结果。 - 查看结果的类型:
:t res,会得到res :: Maybe ([a] -> [a]),这直接证明结果确实是Nothing,只是类型里包含函数没法打印。
内容的提问来源于stack exchange,提问作者Dapeng Li
相关产品推荐
相关产品推荐

