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

lox*_*axs 2 haskell ghc type-parameter

我很困惑的是GHC在看似错误的行为中发生了相当简单的Haskell程序.

请考虑以下代码:

import System.IO
output :: [String] -> IO()
output stringList = sequence_ $ map putStrLn stringList

main :: IO ()

s = show

main = output [
    s 42,
    s True
  ]
Run Code Online (Sandbox Code Playgroud)

在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,
  |
Run Code Online (Sandbox Code Playgroud)

GHC 8.0.2产生相同的错误.

这也发生在以下变化:

但在这三种情况下,替换s = show通过s x = show x解决问题:

main :: IO ()

s x = show x

main = output [
    s 42,
    s True
  ]
Run Code Online (Sandbox Code Playgroud)

$ runghc u.hs
42
True
Run Code Online (Sandbox Code Playgroud)

这不是特定的show.这是一个失败的succ函数操作Enum元素:

main :: IO ()
main = let s = succ in putStrLn $ showList [
    show $ s 41,
    show $ s False
  ] ""
Run Code Online (Sandbox Code Playgroud)

更换s = succs x = succ x还是固定的东西.

我无法找到这种意外行为的解释.这是一个错误吗?如果不是,请解释发生了什么.

typ*_*ris 5

被单态限制所咬,它不是一个bug.该页面的前两段:

"单态限制"是Haskell类型推断中的反直觉规则.如果您忘记提供类型签名,有时此规则将使用"类型默认"规则填充具有特定类型的自由类型变量.生成的类型签名总是比您期望的更少多态,因此通常这会导致编译器在您希望它为多态表达式推断出完美的类型时抛出类型错误.

一个简单的例子是加号=(+).如果没有plus的显式签名,编译器将不会推断类型(+)::(Num a)=> a - > a - > a for plus,但是将应用默认规则来指定plus :: Integer - > Integer - >整数.当应用于plus 3.5 2.7时,GHCi将产生有些误导性的错误,没有来自文字"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
    ]
Run Code Online (Sandbox Code Playgroud)

加载包含此文件的文件后,您将在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>
Run Code Online (Sandbox Code Playgroud)

因此,在您的第一个示例中,推导出的类型s不允许您将其与数字一起使用.

当单态性限制适用时,确切的规则在Haskell Report 2010的第4.5.5节中定义,但是相当技术性.

还要注意单态限制在ghci提示符下被禁用,并且仅适用于已编译的模块.