Ric*_*ruz 6 printf haskell types hindley-milner type-signature
为什么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
Run Code Online (Sandbox Code Playgroud)
这里是不明确的变量时,错误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
Run Code Online (Sandbox Code Playgroud)
Dan*_*ner 12
这是默认规则的一个怪癖,它明确表示只有在上下文中有一组固定的类时,才可以将类型类多态值默认为单态的:
在发现模糊类型的情况下,如果出现以下情况,则模糊类型变量
v
是可以违约的:
v
仅出现在表单的约束中C v
,其中C
是一个类,和- 这些类中至少有一个是数字类(即,
Num
或其子类Num
),和- 所有这些类都在
Prelude
标准库中定义(图6.2-6.3显示了数字类,图6.1显示了在Prelude
.中定义的类.)每个默认变量都由默认列表中的第一个类型替换,该类型是所有模糊变量类的实例.如果没有找到这样的类型,则是静态错误.
(报告的第4.3.4节.)这里令人不安的是第3点,因为PrintfArg a
对类型的限制3 :: (Num a, PrintfArg a) => a
提到了PrintfArg
不在的类Prelude
.
GHC提供了ExtendedDefaultRules
放松这些规则的实用工具,如手册中所述:
找到所有未解决的约束.然后:
- 查找具有类型变量的形式的
(C a)
那些a
,并将这些约束划分为共享公共类型变量的组a
.- 仅保留至少一个类是交互式类的组(在下面定义).
- 现在,对于每个剩余的组G,依次尝试默认类型列表中的每个类型ty ; 如果setting
a
= ty将允许完全解决G中的约束.如果是这样,默认a
为ty.- 单元类型
()
和列表类型[]
将添加到执行类型默认时尝试的标准类型列表的开头.注意任何多参数约束
(D a b)
或(D [a] Int)
不参与过程(无论是帮助还是阻碍); 但是一旦违约过程完成,它们当然必须是可溶的.
事实上,打开这个pragma会使你的文件工作:
{-# LANGUAGE ExtendedDefaultRules #-}
import Text.Printf
main = printf "%d\n" 3
Run Code Online (Sandbox Code Playgroud)