GHCi如何打印由"纯"创建的部分应用值?

Ale*_*ing 5 haskell typeclass applicative

我一直在玩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
Run Code Online (Sandbox Code Playgroud)

但是,如果我创建T一个实例Show,则A在两种情况下都打印出来.

ghci> data T = A deriving (Show)
ghci> pure A
A
ghci> pure A 0
A
Run Code Online (Sandbox Code Playgroud)

我真正不明白的是,如何pure A在两种情况下以不同的方式打印一个值.是不是pure A部分应用?

我理解为什么pure A 0在第一个例子中调用错误而在第二个例子中调用错误 - 这对我来说是有意义的.那是使用的((->) r)实例Applicative,所以它只是产生一个总是返回的函数A.

但是pure,当应用程序本身的类型尚不为人所知时,如何仅使用一个值进行实例化?此外,GHC怎么可能打印这个值?

dfe*_*uer 14

GHCi有点奇特.特别是,当您在提示符下键入表达式时,它会尝试按两种不同的方式解释它,按顺序:

  1. 作为IO执行的动作.
  2. 作为打印出来的价值.

由于IOIS Applicative,它被解释pure A为一种IO类型的生成作用的东西T.它执行该操作(什么都不做),并且由于结果不存在Show,因此不会打印任何内容.如果您创建T了一个实例Show,那么它会为您打印出结果.

当你写作时pure A 0,GHCi看到了这个:

pure :: Applicative f => a -> f a
pure A :: Applicative f => f T
Run Code Online (Sandbox Code Playgroud)

而且因为你申请pure A0,pure A必须是一个函数a->b对于某些类型的ab,并且a必须包含0.

(Num a, Applicative f) => f T ~ (a -> b)
Run Code Online (Sandbox Code Playgroud)

(注意,这x ~ y意味着xy统一 - 它们可以具有相同的类型.)

因此,我们必须有f ~ ((->) a)T ~ b,所以其实GHC推断,在这种情况下,

pure A :: Num a => ((->) a) T
Run Code Online (Sandbox Code Playgroud)

我们可以改写为

pure A :: Num a => a -> T
Run Code Online (Sandbox Code Playgroud)

嗯,(->) a是一个实例Applicative,即"读者",所以这没关系.当我们申请时pure A,0我们得到一些类型T,即A.当然,这不能被解释为一个IO动作,所以如果T不是一个实例Show,GHCi会抱怨.


Ørj*_*sen 7

当您为要评估的GHCi提示提供不明确类型的值时,它会尝试以各种方式默认类型.特别是,它会尝试是否适合某种IO a类型,以防您想要执行IO操作(请参阅GHC手册).在您的情况下,pure A默认为类型IO T.也:

此外,如果(且仅当),GHCi将打印I/O操作的结果:

  • 结果类型是.的实例Show.
  • 结果类型不是().