gpt4 book ai didi

haskell - GHC 8 - 具有重命名函数的约束类型参数化规则

转载 作者:行者123 更新时间:2023-12-02 12:21:46 24 4
gpt4 key购买 nike

我对相当简单的 Haskell 程序中发生的 GHC 看似错误的行为感到困惑。

考虑以下代码:

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。下面是一个在 Enum 元素上运行 succ 函数失败的例子:

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 提示符下被停用,并且仅适用于已编译的模块。

关于haskell - GHC 8 - 具有重命名函数的约束类型参数化规则,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53002848/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com