【问题标题】:Haskell: Why is the type inferred by GHC for main method not quite complete?Haskell:为什么 GHC 为 main 方法推断的类型不完全?
【发布时间】:2011-06-18 15:15:16
【问题描述】:

例如,拿 Don Stewart 写的代码来回答一些 Stack Overflow 问题:

import Control.Monad
import qualified Data.HashTable as H
import System.Environment

main = do
  [size] <- fmap (fmap read) getArgs
  m <- H.new (==) H.hashInt
  forM_ [1..size] $ \n -> H.insert m n n
  v <- H.lookup m 100
  print v

在 GHCi 中加载它。

:t getArgs ---> getArgs :: IO [String]
:t main    ---> main :: IO ()

为什么 main 的类型签名没有反映 getArgs :: IO [String] 被调用的事实?

当你运行二进制文件时,你可以给出一个参数。 &lt;prog&gt; 145 返回Just 100 但在 GHCi 中,您不能:main 145 给出错误。你如何在 GHCi 中运行这个程序并给出一个论点。

【问题讨论】:

    标签: haskell type-inference ghci


    【解决方案1】:

    main 的类型是其最终表达式的类型; print 产生IO (),所以这是main 的类型。中间类型不相关,因为 (&gt;&gt;=) 不会传播除了 monad 之外的任何东西。

    (>>=) :: Monad m => m a -> (a -> m b) -> m b
    

    a 未出现在结果类型 (m b) 中。

    至于在 GHCi 中运行程序,请看:main 命令。

    【讨论】:

    • 谢谢。我知道 do 是 >>= 的语法糖,它的签名是 (>>=) :: (Monad m) => m a -> (a -> m b) -> m b 。但是,即使使用单子操作,编译器也无法利用具有 getArgs :: IO [String] 类型签名的 getArgs 正在计算中的事实?并提供更有意义的类型签名?或者这根本不可能?
    • 不在 Haskell 中.. 我不清楚这样做除了已经存在的东西之外还有什么价值 (IO)。这是对编译器有帮助的信息,但对编译器没有帮助。除非您真正考虑的是拆分 IO,否则这是一个长期讨论的话题,归根结底是一场后勤噩梦。
    • 如果这让您感到困扰,那么只需将所有代码放入 mainX :: [String] -&gt; IO () 函数并使用 main = getArgs &gt;&gt;= mainX
    【解决方案2】:

    你想:set args 的值。例如:

    Prelude> import System.Environment
    Prelude System.Environment> getArgs
    []
    Prelude System.Environment> :set args ["foo","bar"]
    Prelude System.Envrionment> getArgs
    ["foo","bar"]
    

    关于类型签名问题,这里main的类型由print v决定。通过 &gt;&gt; 运算符忽略之前的所有其他内容。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-11-06
      • 1970-01-01
      • 2011-01-21
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多