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

为何GHCI中命名的numDivisor函数比匿名版本性能低约1.4倍?

问题原因

该性能差异本质是GHCi默认配置下,命名函数默认保留多态类型,而就地使用的匿名函数会直接特化为参数的具体类型导致的多态分发开销:

  1. 你使用的GHC 8.6.5版本GHCi默认关闭单态限制,未加类型签名的numDivisor会被推导为Integral a => a -> Int的多态类型,每次调用时都需要额外执行类型类动态分发逻辑,也无法针对具体整数类型做指令级优化。
  2. 就地调用的匿名函数直接绑定到了具体类型的参数x(GHCi中数值字面量默认是Integer类型),求值时会直接特化为Integer -> Int的具体函数,没有多态开销,性能自然更高。
  3. GHCi默认不开启编译优化,不会自动对多态命名函数做调用点特化,进一步放大了两者的性能差距。

解决方法

想要命名函数和匿名函数性能一致,可选择以下方案:

1. 给命名函数添加具体类型签名(最推荐)

直接指定你要使用的整数类型即可:

numDivisor :: Integer -> Int
numDivisor n = length $ filter (\x -> n `mod` x == 0) [1..n]

加完类型签名后再测试,性能就会和匿名版本完全一致。where子句里的局部函数也可以通过加局部类型签名解决问题。

2. 开启单态限制

在GHCi中执行以下命令开启单态限制:

:set -XMonomorphismRestriction

开启后GHC会自动为顶层绑定推导单态类型,不需要加类型签名numDivisor也会被推导为Integer -> Int的具体类型,同样可以消除多态开销。

3. 开启优化(编译场景适用)

如果是把代码写到文件里编译运行,添加-O2参数编译,GHC会自动做函数特化、内联优化,命名和匿名函数性能没有区别,甚至命名函数可以跨模块复用优化结果。也可以手动加内联标记强制GHC在调用点展开:

{-# INLINE numDivisor #-}
numDivisor n = length $ filter (\x -> n `mod` x == 0) [1..n]

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.26 23:57:04