我一直在玩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
错误而在第二个例子中没有调用 - 这对我来说是有意义的。那是使用((->) r)
的{{1}}实例,所以它只会产生一个始终返回Applicative
的函数。
但是,当应用程序本身的类型尚未知晓时,A
如何仅使用一个值进行实例化?此外,GHC怎么可能打印这个值?
答案 0 :(得分:14)
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
{1}}必须包含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
的一个实例,即“读者”,所以这没关系。当我们将pure A
应用于0
时,我们会得到T
类型的内容,即A
。当然,此不能被解释为IO
操作,因此如果T
不是Show
的实例,GHCi会抱怨。
答案 1 :(得分:7)
当您向GHCi提示符提供不明确类型的值以进行评估时,它会尝试以各种方式默认类型。特别是,它会尝试是否适合IO a
类型,以防您想要执行IO操作(请参阅the GHC manual)。在您的情况下,pure A
默认为IO T
类型。也:
此外,如果(且仅当):
,GHCi将打印I / O操作的结果
- 结果类型是
的实例Show
。- 结果类型不是
()
。