GHCi 如何打印从 "pure" 创建的部分应用的值?
How does GHCi print partially-applied values created from "pure"?
我一直在研究 Applicative
个实例以弄清楚它们是如何工作的。但是,老实说,我不理解这种行为。
如果我定义自己的数据类型,然后在没有其他参数的情况下将 pure
应用于它,则不会打印任何内容,但如果我尝试将某些内容应用于结果,则会出错。
ghci> data T = A
ghci> pure A
ghci> pure A 0
<interactive>:21:1:
No instance for (Show T) arising from a use of ‘print’
In a stmt of an interactive GHCi command: print it
但是,如果我使 T
成为 Show
的实例,那么在这两种情况下都会打印出 A
。
ghci> data T = A deriving (Show)
ghci> pure A
A
ghci> pure A 0
A
我真的不明白 pure A
怎么会是一个在两种情况下打印不同的值。 pure A
不是部分应用了吗?
我确实理解为什么在第一个示例中调用 pure A 0
错误而在第二个示例中却没有——这对我来说很有意义。那是使用 Applicative
的 ((->) r)
实例,所以它简单地产生一个总是 returns A
.
的函数
但是,当应用程序本身的类型尚不清楚时,pure
是如何仅用一个值实例化的呢?此外,GHC 怎么可能打印这个值?
当您为 GHCi 提示提供一个模糊类型的值进行评估时,它会尝试以各种方式默认该类型。特别是,它会尝试它是否适合 IO a
类型,以防您要执行 IO 操作(请参阅 the GHC manual)。在您的例子中,pure A
默认为 IO T
类型。还有:
Furthermore, GHCi will print the result of the I/O action if (and only if):
- The result type is an instance of
Show
.
- The result type is not
()
.
GHCi 有点奇怪。特别是,当您在提示符下键入表达式时,它会尝试以两种不同的方式解释它,顺序为:
- 作为要执行的
IO
操作。
- 作为要打印的值。
因为 IO
是 Applicative
,它将 pure A
解释为一个 IO
动作产生类型 T
。它执行该操作(什么都不做),并且由于结果不在 Show
中,因此它不会打印任何内容。如果你使 T
成为 Show
的实例,那么它会为你打印出结果。
当你写 pure A 0
时,GHCi 会看到:
pure :: Applicative f => a -> f a
pure A :: Applicative f => f T
并且由于您将 pure A
应用于 0
,因此 pure A
必须是某些类型 a
和 b
的函数 a->b
, a
必须包含 0
.
(Num a, Applicative f) => f T ~ (a -> b)
(注意x ~ y
表示x
和y
统一——可以使它们具有相同的类型。)
因此我们必须有 f ~ ((->) a)
和 T ~ b
,所以实际上 GHC 推断,在这种情况下,
pure A :: Num a => ((->) a) T
我们可以改写为
pure A :: Num a => a -> T
嗯,(->) a
是Applicative
的一个实例,即"reader",这样就可以了。当我们将 pure A
应用于 0
时,我们得到类型 T
的东西,即 A
。这个 不能 被解释为一个 IO
动作,当然,所以如果 T
不是 Show
的实例,GHCi 会抱怨。
我一直在研究 Applicative
个实例以弄清楚它们是如何工作的。但是,老实说,我不理解这种行为。
如果我定义自己的数据类型,然后在没有其他参数的情况下将 pure
应用于它,则不会打印任何内容,但如果我尝试将某些内容应用于结果,则会出错。
ghci> data T = A
ghci> pure A
ghci> pure A 0
<interactive>:21:1:
No instance for (Show T) arising from a use of ‘print’
In a stmt of an interactive GHCi command: print it
但是,如果我使 T
成为 Show
的实例,那么在这两种情况下都会打印出 A
。
ghci> data T = A deriving (Show)
ghci> pure A
A
ghci> pure A 0
A
我真的不明白 pure A
怎么会是一个在两种情况下打印不同的值。 pure A
不是部分应用了吗?
我确实理解为什么在第一个示例中调用 pure A 0
错误而在第二个示例中却没有——这对我来说很有意义。那是使用 Applicative
的 ((->) r)
实例,所以它简单地产生一个总是 returns A
.
但是,当应用程序本身的类型尚不清楚时,pure
是如何仅用一个值实例化的呢?此外,GHC 怎么可能打印这个值?
当您为 GHCi 提示提供一个模糊类型的值进行评估时,它会尝试以各种方式默认该类型。特别是,它会尝试它是否适合 IO a
类型,以防您要执行 IO 操作(请参阅 the GHC manual)。在您的例子中,pure A
默认为 IO T
类型。还有:
Furthermore, GHCi will print the result of the I/O action if (and only if):
- The result type is an instance of
Show
.- The result type is not
()
.
GHCi 有点奇怪。特别是,当您在提示符下键入表达式时,它会尝试以两种不同的方式解释它,顺序为:
- 作为要执行的
IO
操作。 - 作为要打印的值。
因为 IO
是 Applicative
,它将 pure A
解释为一个 IO
动作产生类型 T
。它执行该操作(什么都不做),并且由于结果不在 Show
中,因此它不会打印任何内容。如果你使 T
成为 Show
的实例,那么它会为你打印出结果。
当你写 pure A 0
时,GHCi 会看到:
pure :: Applicative f => a -> f a
pure A :: Applicative f => f T
并且由于您将 pure A
应用于 0
,因此 pure A
必须是某些类型 a
和 b
的函数 a->b
, a
必须包含 0
.
(Num a, Applicative f) => f T ~ (a -> b)
(注意x ~ y
表示x
和y
统一——可以使它们具有相同的类型。)
因此我们必须有 f ~ ((->) a)
和 T ~ b
,所以实际上 GHC 推断,在这种情况下,
pure A :: Num a => ((->) a) T
我们可以改写为
pure A :: Num a => a -> T
嗯,(->) a
是Applicative
的一个实例,即"reader",这样就可以了。当我们将 pure A
应用于 0
时,我们得到类型 T
的东西,即 A
。这个 不能 被解释为一个 IO
动作,当然,所以如果 T
不是 Show
的实例,GHCi 会抱怨。