如何解释 GHCI 报告的类型

How to interpret types reported by GHCI

当向 GHCI 询问类型时,我往往与理想类型相去甚远(例如,不完全是要放入我的函数签名中的东西,或者在语法上类似于库组合器的文档类型)。

*Main Control.Monad.Shell> :t script
script :: Script f -> text-1.2.1.3:Data.Text.Internal.Lazy.Text

*Main Control.Monad.Shell> :t cmd "echo" "foo"
cmd "echo" "foo" :: CmdParams t => t

为什么 GHCI 显示隐藏的内部类型(甚至包版本),但在第二种情况下,当包(可能)设计为使用别名时显示一般类型?

基本上避免使用非平凡类型的类型推断器并改为查找文档是一种好习惯吗?

更多"popular"库示例:

*Main Control.Lens> :t _2
_2 :: (Functor f, Field2 s t a b) => (a -> f b) -> s -> f t
*Main Control.Lens> :t over
over :: Profunctor p => Setting p s t a b -> p a b -> s -> t
*Main Control.Lens> :t over _2
over _2 :: Field2 s t a b => (a -> b) -> s -> t

ghci 如何描述类型取决于:

  1. 引用的模块是否在范围内?
  2. 引用的包是您的 cabal 项目的一部分吗?

在这种情况下,您会看到内部类型而不是预期的导出类型:

=== file B.hs ===

module B (hello) where
import Data.Text
hello = pack "Hello, world"

=== file A.hs ===
module A where
import B

然后 运行ning ghci A.hs 和命令 :t hello 将报告:

ghci> :t hello
hello :: Data.Text.Internal.Text

但是,如果模块 A 导入 Data.Text:

module A where
import B
import Data.Text

然后 ghci 响应类型查询:

ghci> :t hello
hello :: Text

至于出现在类型名称中的特定包名称,如果 text 未在您的 cabal 文件中明确提及为依赖项,但您从另一个导入 Data.Text 值,则可能会发生这种情况包。

例如,假设上面的模块 B 是 hello 包的一部分,模块 A 是另一个包的一部分,比如 uses-hello.

假设 uses-hello.cabal 文件如下所示:

=== file uses-hello.cabal ===
...
library:
  exposed-modules: A
  build-depends: base, hello
...

请注意 uses-hello text 列为包依赖项,但它可以通过从中导入 B 来使用文本值hello 包。如果你在 uses-hello 包中 运行 cabal repl 你会得到这样的输出:

$ cabal repl
*A> :t hello
hello :: text-1.2.1.1:Data.Text.Internal.Text