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

GHCi无法推导部分IO动作实例:stuff'报错stuff正常的原因与修复

问题描述

在GHCi中执行下述代码时,stuff 4能正常运行,但stuff' 4会抛出错误。请问这一现象的原因是什么?有没有仅用MkStuff'而非MkStuff的修复方法?

代码及执行结果如下:

ghci> 
:{
class MkStuff s m | m -> s where
  stuff:: s -> m ()

instance MkStuff Int IO where
  stuff = print

class MkStuff' s m | m -> s where
  stuff' :: s -> m

instance MkStuff' Int (IO ()) where
  stuff' = print
:}

ghci> stuff 4
4
ghci> stuff' 4

<interactive>:16:1: error: [GHC-39999]
    • No instance for ‘MkStuff' Integer ()’ arising from a use of ‘it’
    • In the first argument of ‘print’, namely ‘it’   
      In a stmt of an interactive GHCi command: print it
问题原因

核心差异在于两个类的返回值类型设计和GHCi的交互逻辑:

  • 对于stuff,它的类型是s -> m ()。调用stuff 4时,GHC能通过MkStuff Int IO实例直接推导:

    • m是IO,返回值为IO ();
    • 4会被自动推导为Int(匹配实例要求的s类型);
    • GHCi遇到IO类型的表达式会自动执行它,不会尝试把它当作普通值打印,因此运行正常。
  • 对于stuff',它的类型是s -> m。调用stuff' 4时,虽然理论上可以通过MkStuff' Int (IO ())实例推导出m是IO ()、4是Int,但GHCi的类型推导出现了歧义:
    GHCi默认会对表达式做两种处理:如果是IO a类型就执行并打印结果;如果是非IO类型就直接打印值。但这里GHCi错误地尝试将stuff' 4的结果当作非IO类型处理,此时4被默认推导为Integer(Haskell字面量默认类型),同时m被约束为(),导致它去寻找不存在的MkStuff' Integer ()实例,最终报错。

修复方法(仅使用MkStuff')

有两种简单的修复方式:

方式一:显式指定返回类型

调用时直接标注stuff' 4的类型,消除推导歧义:

ghci> stuff' 4 :: IO ()
4

方式二:使用类型应用指定参数

开启TypeApplications扩展后,直接指定s的类型为Int,让GHC明确匹配正确的实例:

ghci> :set -XTypeApplications
ghci> stuff' @Int 4
4

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 05:32:45