haskell - 为什么 Haskell 要求对 printf 的数字进行消歧,而不是对 show 进行消歧?

标签 haskell types printf type-signature hindley-milner

为什么是 printf "%d\n" 3模棱两可但不是show 3 ?可以 printf模块被重写以提供自动消歧?大概像 show必须在 printf 的较低级别完成... 或者 printf 之间是否存在一些关键区别?和 show这需要消除数字的歧义?

如果 printf 可以被重写以自动处理数字而没有明确的歧义,那么 show 是什么?做对了吗? show如何将数字转换为不带 :: Int 的字符串printf的消歧?

这里是show的正确操作(没有任何歧义)以及printf的正确操作(有歧义):

$ cat printStrLnShow3
import Text.Printf
main = putStrLn (show 3)
$ runghc printStrLnShow3
3
$ cat printfWithInt3
import Text.Printf
main = printf "%d\n" (3 :: Int)
$ runghc printfWithInt3
3

这是 printf 时的模棱两可的变量错误。 不是 消除数字歧义:
$ cat printfWithAmbiguous3
import Text.Printf
main = printf "%d\n" 3
$ runghc printfWithAmbiguous3

printfWithAmbiguous3:2:8:
    No instance for (PrintfArg a0) arising from a use of `printf'
    The type variable `a0' is ambiguous
    Possible fix: add a type signature that fixes these type variable(s)
    Note: there are several potential instances:
      instance [safe] PrintfArg Char -- Defined in `Text.Printf'
      instance [safe] PrintfArg Double -- Defined in `Text.Printf'
      instance [safe] PrintfArg Float -- Defined in `Text.Printf'
      ...plus 12 others
    In the expression: printf "%d" 3
    In an equation for `main': main = printf "%d" 3

printfWithAmbiguous3:2:22:
    No instance for (Num a0) arising from the literal `3'
    The type variable `a0' is ambiguous
    Possible fix: add a type signature that fixes these type variable(s)
    Note: there are several potential instances:
      instance Num Double -- Defined in `GHC.Float'
      instance Num Float -- Defined in `GHC.Float'
      instance Integral a => Num (GHC.Real.Ratio a)
        -- Defined in `GHC.Real'
      ...plus 11 others
    In the second argument of `printf', namely `3'
    In the expression: printf "%d" 3
    In an equation for `main': main = printf "%d" 3

最佳答案

这是默认规则的一个怪癖,它明确表示只有当上下文中有一组固定的类时,您才可以将类型类多态值默认为单态值:

In situations where an ambiguous type is discovered, an ambiguous type variable, v, is defaultable if:

  • v appears only in constraints of the form C v, where C is a class, and
  • at least one of these classes is a numeric class, (that is, Num or a subclass of Num), and
  • all of these classes are defined in the Prelude or a standard library (Figures 6.2–6.3 show the numeric classes, and Figure 6.1 shows the classes defined in the Prelude.)

Each defaultable variable is replaced by the first type in the default list that is an instance of all the ambiguous variable’s classes. It is a static error if no such type is found.



(报告的 Section 4.3.4。)这里令人不安的是要点 3,因为 PrintfArg a3 :: (Num a, PrintfArg a) => a 类型的约束提到类(class)PrintfArg不在 Prelude 中.

GHC 提供 ExtendedDefaultRules pragma 放宽这些规则,如 the manual 中所述:

Find all the unsolved constraints. Then:

  • Find those that are of form (C a) where a is a type variable, and partition those constraints into groups that share a common type variable a.
  • Keep only the groups in which at least one of the classes is an interactive class (defined below).
  • Now, for each remaining group G, try each type ty from the default-type list in turn; if setting a = ty would allow the constraints in G to be completely solved. If so, default a to ty.
  • The unit type () and the list type [] are added to the start of the standard list of types which are tried when doing type defaulting.

Note that any multi-parameter constraints (D a b) or (D [a] Int) do not participate in the process (either to help or to hinder); but they must of course be soluble once the defaulting process is complete.



事实上,打开这个 pragma 会让你的文件工作:
{-# LANGUAGE ExtendedDefaultRules #-}
import Text.Printf
main = printf "%d\n" 3

关于haskell - 为什么 Haskell 要求对 printf 的数字进行消歧,而不是对 show 进行消歧?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46793849/

相关文章:

c++ - 我们可以在类型上定义结构吗?

java - Java 中的不兼容类型错误

c - 当字符串具有变量时使用列填充打印

c - 在C中搜索多个单词,并在它们后面显示以逗号分隔的信息

c - printf() 的行为

haskell - Haskell 中产品类型和元组的冗余

haskell - 有哪些适合初学者的 Haskell Primers/Tutorials?

haskell - 导入语法 `import "cryptonite"Crypto.Hash` 中带引号的字符串是什么意思?

c++ - 检查对象的类型是否继承自特定类

haskell - 简单函数中的类型混淆