为什么是 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 formC v
, whereC
is a class, and- at least one of these classes is a numeric class, (that is,
Num
or a subclass ofNum
), 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 thePrelude
.)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 a
对 3 :: (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)
wherea
is a type variable, and partition those constraints into groups that share a common type variablea
.- 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, defaulta
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/