在模块中,System.Info
我看到以下功能:
os :: String arch :: String compilerName :: String compilerVersion :: Version
为什么没有IO
那里?他们正在访问系统...我错了吗?我的期望是:
os :: IO String arch :: IO String compilerName :: IO String compilerVersion :: IO Version
用例:
os :: String arch :: String compilerName :: String compilerVersion :: Version
chepner.. 26
您不会在运行时获得该信息。它们在系统中安装时在编译器中进行了硬编码。
如果你看一下定义,这是最明显的compilerName
,如发现http://hackage.haskell.org/package/base-4.12.0.0/docs/src/System.Info.html。
compilerName :: String compilerName = "ghc"
但即使像 os
os :: String os = HOST_OS
可以使用未定义的名称HOST_OS
(以大写字母开头的值??)来定义,这表示只是一个占位符,在安装过程中会被替换。
有人也可以纠正我(请!),但是该{-# LANGUAGE CPP #-}
文件顶部的编译指示建议HOST_OS
在编译之前用C预处理程序将类似的字符串替换为适当的字符串。
您不会在运行时获得该信息。它们在系统中安装时在编译器中进行了硬编码。
如果你看一下定义,这是最明显的compilerName
,如发现http://hackage.haskell.org/package/base-4.12.0.0/docs/src/System.Info.html。
compilerName :: String compilerName = "ghc"
但即使像 os
os :: String os = HOST_OS
可以使用未定义的名称HOST_OS
(以大写字母开头的值??)来定义,这表示只是一个占位符,在安装过程中会被替换。
有人也可以纠正我(请!),但是该{-# LANGUAGE CPP #-}
文件顶部的编译指示建议HOST_OS
在编译之前用C预处理程序将类似的字符串替换为适当的字符串。
这个问题是一个好问题。答案是这样的:每个程序编译这些值都是静态的。它们本质上已编译到程序中,此后再也不会更改。因此,如果将它们视为常量,则任何东西(在GHC使用的假设下)都不会中断。而且,使用简单的常量比执行IO操作更为方便。
但这就是所有的遗留推理。Haskell是一门古老的语言。(不,它比Java早了几年。)已经建立了许多不再被认为是最佳实践的推理库。这些就是例子。暴露它们的现代库很可能会使它们执行IO操作,即使编译后结果不变。将不是源常量的东西放在IO操作后面会更有用,尽管仍然存在一些值得注意的例外,例如Int
在32位和64位平台之间更改大小。
无论如何...我想说的是您的期望是坚定的,而这些类型是历史古怪的结果。