我一直在使用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)错误,这对我来说很有意义。那是使用ApplicativeA实例,因此它只是产生一个始终返回pure的函数。

但是,当尚不知道应用程序本身的类型时,如何仅用一个值实例化ojit_code?此外,GHC如何打印此值?

最佳答案

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

  • 作为要执行的IO操作。
  • 作为要打印的值。

  • 由于IOApplicative,因此它将pure A解释为IO Action ,产生的类型为T。它执行该操作(不执行任何操作),并且由于结果不在Show中,因此它不会打印出任何内容。如果您将T设置为Show的实例,那么它将为您打印出结果。

    当您编写pure A 0时,GHCi会看到以下内容:
    pure :: Applicative f => a -> f a
    pure A :: Applicative f => f T
    

    并且由于将pure A应用于0,对于某些类型pure Aa->ba必须是函数b,并且a必须包含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 Action ,因此,如果T不是Show的实例,则GHCi会提示。

    关于haskell - GHCi如何打印从 “pure”创建的部分应用的值?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/28978857/

    10-13 02:31