GHC 8 - 具有重命名函数的约束类型参数化规则
GHC 8 - Constrained type parameterization rules with renamed functions
我对 GHC 在相当简单的 Haskell 程序中出现的看似错误的行为感到困惑。
考虑以下代码:
import System.IO
output :: [String] -> IO()
output stringList = sequence_ $ map putStrLn stringList
main :: IO ()
s = show
main = output [
s 42,
s True
]
在 GHC 8.4.3 中产生以下输出:
$ runghc parameterize.hs
.hs:9:7: error:
• No instance for (Num Bool) arising from the literal ‘42’
• In the first argument of ‘s’, namely ‘42’
In the expression: s 42
In the first argument of ‘output’, namely ‘[s 42, s True]’
|
9 | s 42,
|
GHC 8.0.2 产生同样的错误。
以下变体也会发生这种情况:
使用where
main :: IO ()
main = output [
s 42,
s True
]
where s = show
使用let ... in
main :: IO ()
main = let s = show in output [
s 42,
s True
]
但是在这三种情况下,将s = show
替换为s x = show x
就解决了问题:
main :: IO ()
s x = show x
main = output [
s 42,
s True
]
$ runghc u.hs
42
True
这不是 show
特有的。这是一个失败的 succ
函数在 Enum
元素上运行:
main :: IO ()
main = let s = succ in putStrLn $ showList [
show $ s 41,
show $ s False
] ""
用 s x = succ x
替换 s = succ
仍然可以解决问题。
我找不到对这种意外行为的解释。这是一个错误吗?如果不是,请解释发生了什么。
你被 monomorphism restriction 咬伤了,这不是虫子。该页的前两段:
The "monomorphism restriction" is a counter-intuitive rule in Haskell
type inference. If you forget to provide a type signature, sometimes
this rule will fill the free type variables with specific types using
"type defaulting" rules. The resulting type signature is always less
polymorphic than you'd expect, so often this results in the compiler
throwing type errors at you in situations where you expected it to
infer a perfectly sane type for a polymorphic expression.
A simple example is plus = (+). Without an explicit signature for
plus, the compiler will not infer the type (+) :: (Num a) => a -> a ->
a for plus
, but will apply defaulting rules to specify plus ::
Integer -> Integer -> Integer. When applied to plus 3.5 2.7, GHCi will
then produce the somewhat-misleading-looking error, No instance for
(Fractional Integer) arising from the literal ‘3.5’.
只需将此处的 (+)
替换为 show
,这就是您的示例。
以这段代码为例:
import System.IO
output :: [String] -> IO()
output stringList = sequence_ $ map putStrLn stringList
main :: IO ()
s = show
s2 x = show x
main = do
output [
s False,
s True
]
output [
s2 42,
s2 True
]
加载包含以下内容的文件后,您会在 ghci 中得到以下结果:
Prelude> :l test.hs
[1 of 1] Compiling Main ( test.hs, interpreted )
Ok, one module loaded.
*Main> :t s
s :: Bool -> String
*Main> :t s2
s2 :: Show a => a -> String
*Main>
因此,在您的第一个示例中,为 s
推导的类型不允许您将其与数字一起使用。
此处定义了适用单态限制的确切规则 Section 4.5.5 of Haskell Report 2010,但相当技术性。
另请注意,单态性限制在 ghci 提示符下已停用,仅适用于已编译的模块。
我对 GHC 在相当简单的 Haskell 程序中出现的看似错误的行为感到困惑。
考虑以下代码:
import System.IO
output :: [String] -> IO()
output stringList = sequence_ $ map putStrLn stringList
main :: IO ()
s = show
main = output [
s 42,
s True
]
在 GHC 8.4.3 中产生以下输出:
$ runghc parameterize.hs
.hs:9:7: error:
• No instance for (Num Bool) arising from the literal ‘42’
• In the first argument of ‘s’, namely ‘42’
In the expression: s 42
In the first argument of ‘output’, namely ‘[s 42, s True]’
|
9 | s 42,
|
GHC 8.0.2 产生同样的错误。
以下变体也会发生这种情况:
使用
where
main :: IO () main = output [ s 42, s True ] where s = show
使用
let ... in
main :: IO () main = let s = show in output [ s 42, s True ]
但是在这三种情况下,将s = show
替换为s x = show x
就解决了问题:
main :: IO ()
s x = show x
main = output [
s 42,
s True
]
$ runghc u.hs
42
True
这不是 show
特有的。这是一个失败的 succ
函数在 Enum
元素上运行:
main :: IO ()
main = let s = succ in putStrLn $ showList [
show $ s 41,
show $ s False
] ""
用 s x = succ x
替换 s = succ
仍然可以解决问题。
我找不到对这种意外行为的解释。这是一个错误吗?如果不是,请解释发生了什么。
你被 monomorphism restriction 咬伤了,这不是虫子。该页的前两段:
The "monomorphism restriction" is a counter-intuitive rule in Haskell type inference. If you forget to provide a type signature, sometimes this rule will fill the free type variables with specific types using "type defaulting" rules. The resulting type signature is always less polymorphic than you'd expect, so often this results in the compiler throwing type errors at you in situations where you expected it to infer a perfectly sane type for a polymorphic expression.
A simple example is plus = (+). Without an explicit signature for plus, the compiler will not infer the type (+) :: (Num a) => a -> a -> a for
plus
, but will apply defaulting rules to specify plus :: Integer -> Integer -> Integer. When applied to plus 3.5 2.7, GHCi will then produce the somewhat-misleading-looking error, No instance for (Fractional Integer) arising from the literal ‘3.5’.
只需将此处的 (+)
替换为 show
,这就是您的示例。
以这段代码为例:
import System.IO
output :: [String] -> IO()
output stringList = sequence_ $ map putStrLn stringList
main :: IO ()
s = show
s2 x = show x
main = do
output [
s False,
s True
]
output [
s2 42,
s2 True
]
加载包含以下内容的文件后,您会在 ghci 中得到以下结果:
Prelude> :l test.hs
[1 of 1] Compiling Main ( test.hs, interpreted )
Ok, one module loaded.
*Main> :t s
s :: Bool -> String
*Main> :t s2
s2 :: Show a => a -> String
*Main>
因此,在您的第一个示例中,为 s
推导的类型不允许您将其与数字一起使用。
此处定义了适用单态限制的确切规则 Section 4.5.5 of Haskell Report 2010,但相当技术性。
另请注意,单态性限制在 ghci 提示符下已停用,仅适用于已编译的模块。