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

标签 haskell ghc type-parameter

我对相当简单的 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/

相关文章:

java - 确保参数化类型具有特定的方法

haskell - 你如何在 Haskell 中构建一个有状态的模块?

haskell - 如何在 Haskell 中编写函数?

haskell - 当什么都没有改变时,如何阻止 GHC 重新编译模块?

haskell - ApplicativeDo 语言扩展 `Parsing` applicative 仍在寻找 Monad 实例

haskell - 读取超过 2^18 字节的惰性字节串时发生段错误

haskell - OCaml 相当于模式匹配中 Haskell 的 @(又名 as-pattern)

list - 重载 "zipWith"支持嵌套列表

Scala将类型参数传递给对象

java - Wild FJ 论文中类型变量和类型参数的区别?