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

为何mth4在文件与GHCi交互环境中定义时类型不同?

为何函数mth4在文件中定义与直接在GHCi交互环境中定义时类型不同?

问题重现

文件定义(test2.hs)

mth1 x y z = x * y * z
mth2 x y = \z -> x * y * z
mth3 x = \y -> \z -> x * y * z
mth4 = \x -> \y -> \z -> x * y * z

加载到GHCi后,mth4的类型为:

mth4 :: Integer -> Integer -> Integer -> Integer

GHCi直接定义

在GHCi中直接输入定义后,mth4的类型为:

mth4 :: Num a => a -> a -> a -> a

原因分析

这是**Haskell单态限制(Monomorphism Restriction)**的行为差异导致的:

  • 文件编译/加载场景:默认启用单态限制。该规则针对无显式类型签名的顶级绑定(如mth4这种不带参数的定义),会将其推断为单态类型(而非多态)。GHC会选择Integer作为Num类型类的默认实例,因此mth4被推断为Integer专用的函数。而mth1/mth2/mth3因为带有显式参数,属于函数绑定,单态限制对其不生效,所以保留多态类型。
  • GHCi交互场景:默认关闭单态限制(启用NoMonomorphismRestriction扩展)。此时所有无显式类型签名的绑定都会被推断为多态类型,因此mth4的类型保留了Num a =>的多态约束。

验证与解决方法

  1. 让文件中的mth4变为多态:在文件开头添加扩展声明,关闭单态限制:
    {-# LANGUAGE NoMonomorphismRestriction #-}
    mth1 x y z = x * y * z
    mth2 x y = \z -> x * y * z
    mth3 x = \y -> \z -> x * y * z
    mth4 = \x -> \y -> \z -> x * y * z
    
    重新加载后,mth4的类型会变为Num a => a -> a -> a -> a。
  2. 显式指定类型签名:给mth4添加多态类型签名,强制保留多态性:
    mth4 :: Num a => a -> a -> a -> a
    mth4 = \x -> \y -> \z -> x * y * z
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 22:30:19