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

时间:2015-03-11 04:56:36

标签: 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

但是,如果我将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怎么可能打印这个值?

2 个答案:

答案 0 :(得分:14)

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

  1. 执行IO操作。
  2. 作为打印的值。
  3. 由于IOApplicative,因此它会将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应用于0pure A必须是某些类型a->ba以及{b的函数a {1}}必须包含0

    (Num a, Applicative f) => f T ~ (a -> b)
    

    (请注意,x ~ y表示xy统一 - 可以使它们具有相同的类型。)

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

    pure A :: Num a => ((->) a) T
    

    我们可以将其重写为

    pure A :: Num a => a -> T
    

    嗯,(->) aApplicative的一个实例,即“读者”,所以这没关系。当我们将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
  • 的实例   
  • 结果类型不是()
  •