【问题标题】:Type annotation required on overloaded literals when passed to printf传递给 printf 时重载文字所需的类型注释
【发布时间】:2016-03-21 03:07:32
【问题描述】:

我对这些感到困惑:

当我这样写

main = do
    putStrLn . printf "%f" $ 2.3

会导致

(PrintfArg a0) 没有因使用 printf 而产生的实例

类型变量a0不明确

代码在 GHCi 中运行良好,当我在终端中使用 runhaskell 时发生此错误。

所以我写了

putStrLn . printf "%f" $ (2.3 :: Double)

没关系,但我不知道原因。

不要"%f"推断2.3属于类型Double

据我所知,putStrLn 的类型为String -> IO(),当2.3 未被Double 修饰时,printf 的结果不能转换为String 吗?

【问题讨论】:

    标签: haskell printf type-inference


    【解决方案1】:

    由于 Haskell 不是依赖类型的语言,printf 的第一个参数(即您的情况下为 "%f")的 无法指定 类型 printf 的第二个参数的强>(在您的情况下为 2.3)。

    就其本身而言,2.3 的类型是 Fractional a => a,因为它是 overloaded literalprintf's type 可能看起来有点神奇,因为它非常多态,例如printf "%s" "foo"printf "%f" 2.3 都可以进行类型检查。这是通过PrintfTypePrintfArg 类型类实现的。

    总而言之,在printf "%f" 2.3 中,类型检查器只知道2.3 是某种类型a,它同时具有FractionalPrintfArg 实例;但它不知道a 实际上需要什么。它需要一种类型,以便解析FractionalPrintfArg 实例。

    这种情况有点类似于show . read 问题,而您的示例在GHCi 中有效,因为Num defaultingDouble

    【讨论】:

    • 需要注意的是,如果你打开-Wall,当一个(可能非常复杂的)表达式发生默认值时,编译器会警告你,这样适用于默认值的代码将不再“神奇地” " 只在某些时候起作用。
    • 感谢您的回答。当haskell本身无法推断出具体类型(只是推断出一些类型类约束)时,我是否可以认为每个变量都应该使用具体类型来规定。
    • 不一定。如果你有变量“转义”定义的类型,那么有剩余约束是可以的;例如foo x = (show x, show x)(Show a) => a -> (String, String) 处完全有效且可键入,因为类型变量a 出现在其类型中,因此它可能是“别人的问题”。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-04-27
    相关资源
    最近更新 更多