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
相关产品推荐
相关产品推荐

