代码之家  ›  专栏  ›  技术社区  ›  loxaxs

具有重命名函数的ghc8约束类型参数化规则

  •  2
  • loxaxs  · 技术社区  · 8 年前

    考虑以下代码:

    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 = succ s x = succ x 还是能解决问题。

    我一直找不到对这种意外行为的解释。是虫子吗?如果不是,请解释发生了什么。

    1 回复  |  直到 8 年前
        1
  •  5
  •   typetetris    8 年前

    monomorphism restriction 它不是虫子。该页的前两段:

    此规则将使用特定类型填充自由类型变量 多态性超出了您的预期,因此这通常会导致编译器 在预期的情况下向您抛出类型错误 推断一个多态表达的完全正常的类型。

    一个简单的例子是plus=(+)。没有明确的签名 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
        ]
    

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

    推荐文章