如果我启动ghci并输入一个简单的算术表达式,我通常会得到预期的结果。
GHCi λ: 6 * 7
42
然而,我正在遵循一个教程中的例子,这是一个阴谋项目的一部分。如果我在项目中启动ghci,例如cabal repl Example
并尝试相同的表达式,我会得到以下结果:
GHCi λ: 6 * 7
<interactive>:4:1: error: [-Wtype-defaults, -Werror=type-defaults]
• Defaulting the following constraints to type ‘Integer’
(Show a0) arising from a use of ‘print’ at <interactive>:4:1-5
(Num a0) arising from a use of ‘it’ at <interactive>:4:1-5
• In a stmt of an interactive GHCi command: print it
我必须指定表达式的类型:
GHCi λ: 6 * 7 :: Int
42
我想了解是什么可能使'show'在教程的项目中更挑剔,如果有一些方法可以回到'明智的'默认值的便利。
你的问题与Haskell如何处理数字字面量有关:有人可能会认为像6
这样的数字具有Int
(或Integer
)类型;但是,如果您询问ghci6
的类型,您将得到:
λ> :t 6
6 :: Num p => p
这意味着6
(或任何数字字面量)实际上是一个泛型p
的值,前提是p
有一个Num
实例。通常,由于类型注释,编译器能够自动理解您实际需要的数字类型:
plus2 :: Int -> Int
plus2 x = x + 2
-- ^
-- since x has type Int (and Int has a Num instance)
-- 2 is considered an Int as well
当编译器不能理解你需要的类型字面量的具体类型时,它将默认为Integer
,例如,如果你写:
print 2
-- print :: Show a => a -> IO ()
-- 2 :: Num p => p
这里print (2 :: Int)
和print (2 :: Integer)
都是正确的,所以编译器默认为2 :: Integer
。这种默认行为可能并不总是好的(特别是因为Integer
s比Int
s效率低),所以每次发生这种情况时,都会有一个GHC编译标志警告你。
您的项目的.cabal
必须启用-Wtype-defaults
和-Werror
标志。如果你删除了-Werror
,你仍然会看到这个默认行为的警告,但至少你的代码会执行;您也可以删除-Wtype-defaults
来禁用警告。如果您在.cabal
文件中没有看到-Wtype-default
,这是因为它也可以通过指定以下标志之一来启用:-Wall
,-Weverithing
。
TL;DR您应该从项目的.cabal
文件中删除这些编译标志之一:
-Wtype-defaults
(或-Wall
/-Weverithing
)-Werror